Interval form: x to: y when x > y - or how to count down...
I've just been caught out with Intervals - why can't you do: 5 to: 1 do: [ :i | Transcript show: i printString] (eg a negative interval)? if you want to iterate down a series of numbers do you really have to do: 5 to: 1 by: -1 do: [⦠I always assumed that if x > y the step was automatically -1 (but its not). I asked on Discord - and someone pointed out that if you use variables it could be ambiguous - but is it really? I donât know if other smalltalks do it this way (I vaguely recall Dolphin going down, but not sure). Either way the Interval comment should mention this - and Iâll correct it when I get the wisdom of the crowd here. Tim
On 22/02/2019 15:57, Tim Mackinnon wrote:
I've just been caught out with Intervals - why can't you do: 5 to: 1 do: [ :i | Transcript show: i printString] (eg a negative interval)?
if you want to iterate down a series of numbers do you really have to do: 5 to: 1 by: -1 do: [â¦
I always assumed that if x > y the step was automatically -1 (but its not).
Expectations are obviously personal, but as far as I am concerned, I'd expect to see the behavior that Pharo implements. If you don't specify by:, you get a default value of 1. That's much simpler than a default value depending on the bounds of the interval. Konrad.
If itâs always been that way - and things rely on it, sure. But it doesnât feel like the Smalltalk way to me. Having to know about adding -1 seems very C, whereas Smalltalk always seems more natural ... and 5 to: 1 seems like you would count down, not be an empty range and do nothing. But as you say, itâs personal. Iâm still curious though. Tim Sent from my iPhone
On 22 Feb 2019, at 16:13, Konrad Hinsen <konrad.hinsen@fastmail.net> wrote:
On 22/02/2019 15:57, Tim Mackinnon wrote: I've just been caught out with Intervals - why can't you do: 5 to: 1 do: [ :i | Transcript show: i printString] (eg a negative interval)?
if you want to iterate down a series of numbers do you really have to do: 5 to: 1 by: -1 do: [â¦
I always assumed that if x > y the step was automatically -1 (but its not).
Expectations are obviously personal, but as far as I am concerned, I'd expect to see the behavior that Pharo implements. If you don't specify by:, you get a default value of 1. That's much simpler than a default value depending on the bounds of the interval.
Konrad.
On 22 Feb 2019, at 22:35, Tim Mackinnon <tim@testit.works> wrote:
If itâs always been that way - and things rely on it, sure.
But it doesnât feel like the Smalltalk way to me.
Having to know about adding -1 seems very C, whereas Smalltalk always seems more natural ... and 5 to: 1 seems like you would count down, not be an empty range and do nothing.
But as you say, itâs personal. Iâm still curious though.
I personally would find it cool if 10 to: 1 counted down, it feels natural. But I must say I haven't thought it through. I do known that Interval is a class that leads to lots of discussions and disagreements.
Tim
Sent from my iPhone
On 22 Feb 2019, at 16:13, Konrad Hinsen <konrad.hinsen@fastmail.net> wrote:
On 22/02/2019 15:57, Tim Mackinnon wrote: I've just been caught out with Intervals - why can't you do: 5 to: 1 do: [ :i | Transcript show: i printString] (eg a negative interval)?
if you want to iterate down a series of numbers do you really have to do: 5 to: 1 by: -1 do: [â¦
I always assumed that if x > y the step was automatically -1 (but its not).
Expectations are obviously personal, but as far as I am concerned, I'd expect to see the behavior that Pharo implements. If you don't specify by:, you get a default value of 1. That's much simpler than a default value depending on the bounds of the interval.
Konrad.
On 22/2/19 16:57, Sven Van Caekenberghe wrote:
On 22 Feb 2019, at 22:35, Tim Mackinnon <tim@testit.works> wrote:
If itâs always been that way - and things rely on it, sure.
But it doesnât feel like the Smalltalk way to me.
Having to know about adding -1 seems very C, whereas Smalltalk always seems more natural ... and 5 to: 1 seems like you would count down, not be an empty range and do nothing.
But as you say, itâs personal. Iâm still curious though. I personally would find it cool if
10 to: 1
counted down, it feels natural. But I must say I haven't thought it through.
I do known that Interval is a class that leads to lots of discussions and disagreements.
I agree with Tim and Sven: "bigger to: smaller" should count backwards, if we think in the way we used on a day to day expectation. Cheers, Offray
Of the couple of hundred programming languages I have used, there is precisely one that does what you expect (the S programming language, as implemented in R). And it is a major pain in the posterior with no upside that I can discern. Suppose I want a sequence of n consecutive integers beginning with 1. In Smalltalk, (1 to: n) does the job. In R, 1:n *almost* does the job. But what happens when n = 0? Smalltalk gives me the right answer: an empty sequence. R gives me (1,0). That means that *every* *flaming* *time* I write for (i in 1:n) {...} I have to take special care to ensure that n is not 0, sometimes even having to whack in an extra if (n > 0) for (i in 1:n) {...} Trawling through my Smalltalk code, I find that about 6.8% of my counted loops are by: -1, 0.7% of them are by: a negative number other than -1, 2.5% of them are by: a positive number other than 1, 90 % are just to:do: with no by: Inspecting some of the 90% showed that many of them would go catastrophically wrong if 1 to: 0 do: performed its body On Sat, 23 Feb 2019 at 03:58, Tim Mackinnon <tim@testit.works> wrote:
I've just been caught out with Intervals - why can't you do: 5 to: 1 do: [ :i | Transcript show: i printString] (eg a negative interval)?
if you want to iterate down a series of numbers do you really have to do: 5 to: 1 by: -1 do: [â¦
I always assumed that if x > y the step was automatically -1 (but its not).
I asked on Discord - and someone pointed out that if you use variables it could be ambiguous - but is it really? I donât know if other smalltalks do it this way (I vaguely recall Dolphin going down, but not sure).
Either way the Interval comment should mention this - and Iâll correct it when I get the wisdom of the crowd here.
Tim
Hi Richard - but why would you expect 1 to: 0 to give you an empty sequence? If I inspect â0 to: 1â I see: 1 -> 0 2 -> 1 So I would expect â1 to: 0â to see: 1 -> 1 2 -> 0. I asked for a sequence going from 1 down to 0 (in my mind). Knowing about all the by: -1 stuff seems very Câish. Of course, I get that maybe it will break peoples existing code (and maybe that would be why it never gets changed) - but it still feels very strange. Or am I missing something? Tim
On 28 Feb 2019, at 12:38, Richard O'Keefe <raoknz@gmail.com> wrote:
Of the couple of hundred programming languages I have used, there is precisely one that does what you expect (the S programming language, as implemented in R). And it is a major pain in the posterior with no upside that I can discern.
Suppose I want a sequence of n consecutive integers beginning with 1. In Smalltalk, (1 to: n) does the job. In R, 1:n *almost* does the job. But what happens when n = 0? Smalltalk gives me the right answer: an empty sequence. R gives me (1,0). That means that *every* *flaming* *time* I write for (i in 1:n) {...} I have to take special care to ensure that n is not 0, sometimes even having to whack in an extra if (n > 0) for (i in 1:n) {...}
Trawling through my Smalltalk code, I find that about 6.8% of my counted loops are by: -1, 0.7% of them are by: a negative number other than -1, 2.5% of them are by: a positive number other than 1, 90 % are just to:do: with no by: Inspecting some of the 90% showed that many of them would go catastrophically wrong if 1 to: 0 do: performed its body
On Sat, 23 Feb 2019 at 03:58, Tim Mackinnon <tim@testit.works> wrote: I've just been caught out with Intervals - why can't you do: 5 to: 1 do: [ :i | Transcript show: i printString] (eg a negative interval)?
if you want to iterate down a series of numbers do you really have to do: 5 to: 1 by: -1 do: [â¦
I always assumed that if x > y the step was automatically -1 (but its not).
I asked on Discord - and someone pointed out that if you use variables it could be ambiguous - but is it really? I donât know if other smalltalks do it this way (I vaguely recall Dolphin going down, but not sure).
Either way the Interval comment should mention this - and Iâll correct it when I get the wisdom of the crowd here.
Tim
I would expect 1:0 to give me an empty sequence because (a) for all other natural numbers n, 1:n gives me a sequence of n numbers, and (b) how else am I supposed to get an empty sequence? Under your interpretation, (x to: y) would never be empty. This has absolutely nothing to do with C. As I commented, every programming language I know except S uses a default increment of +1 in counted loops, if it allows default increments at all. Fortran, Algol 68, Pascal, PL/I, the seq(1) command in Unix, Haskell, the `seq' function in Erlang, between/3 in Prolog, OCaml, F#, InterLISP-D, and so it goes. Fortran is an interesting case, because Fortran 66 left DO label id = lower,upper unspecified when lower > upper and several compilers made such loops execute once, to the point where programmer tended to think the standard required that, but Fortran 77 nailed it down: NO iterations in that case. Here's a typical use of #to:do: s := 0. 1 to: a size do: [:i | a at: i put: (s := (a at: i) + s)]. Why would you think it a good idea for this to crash if the array is empty? Smalltalk being Smalltalk, nothing stops you adding through: end do: aBlock self to: end by: (end < self ifTrue: [-1] ifFalse: [1]) do: aBlock. to Integer if you really want to. Oh, there's an ambiguity. Should 5 through 1 mean 5,4,3,2,1 or 1,2,3,4,5? Both can be argued for. On Fri, 1 Mar 2019 at 02:03, Tim Mackinnon <tim@testit.works> wrote:
Hi Richard - but why would you expect 1 to: 0 to give you an empty sequence?
If I inspect â0 to: 1â I see: 1 -> 0 2 -> 1
So I would expect â1 to: 0â to see: 1 -> 1 2 -> 0.
I asked for a sequence going from 1 down to 0 (in my mind). Knowing about all the by: -1 stuff seems very Câish.
Of course, I get that maybe it will break peoples existing code (and maybe that would be why it never gets changed) - but it still feels very strange. Or am I missing something?
Tim
On 28 Feb 2019, at 12:38, Richard O'Keefe <raoknz@gmail.com> wrote:
Of the couple of hundred programming languages I have used, there is precisely one that does what you expect (the S programming language, as implemented in R). And it is a major pain in the posterior with no upside that I can discern.
Suppose I want a sequence of n consecutive integers beginning with 1. In Smalltalk, (1 to: n) does the job. In R, 1:n *almost* does the job. But what happens when n = 0? Smalltalk gives me the right answer: an empty sequence. R gives me (1,0). That means that *every* *flaming* *time* I write for (i in 1:n) {...} I have to take special care to ensure that n is not 0, sometimes even having to whack in an extra if (n > 0) for (i in 1:n) {...}
Trawling through my Smalltalk code, I find that about 6.8% of my counted loops are by: -1, 0.7% of them are by: a negative number other than -1, 2.5% of them are by: a positive number other than 1, 90 % are just to:do: with no by: Inspecting some of the 90% showed that many of them would go catastrophically wrong if 1 to: 0 do: performed its body
On Sat, 23 Feb 2019 at 03:58, Tim Mackinnon <tim@testit.works> wrote:
I've just been caught out with Intervals - why can't you do: 5 to: 1 do: [ :i | Transcript show: i printString] (eg a negative interval)?
if you want to iterate down a series of numbers do you really have to do: 5 to: 1 by: -1 do: [â¦
I always assumed that if x > y the step was automatically -1 (but its not).
I asked on Discord - and someone pointed out that if you use variables it could be ambiguous - but is it really? I donât know if other smalltalks do it this way (I vaguely recall Dolphin going down, but not sure).
Either way the Interval comment should mention this - and Iâll correct it when I get the wisdom of the crowd here.
Tim
On 28/02/19 6:33 PM, Tim Mackinnon wrote:
So I would expect â1 to: 0â to see: 1 -> 1 2 -> 0.
It is difficult for code to guess the intent of the coder. Did the coder intend an decreasing sequence or a stopping condition (i == end or i > end?). Perhaps, we could use an explicit selector: 5 downto: 1 to disambiguate between the two cases. Regards .. Subbu
Actually thats quite a good suggestion - it probably should have been: #upTo: #downTo: #to:by: In the first place (but Iâm guessing this change will never happen)
On 1 Mar 2019, at 05:35, K K Subbu <kksubbu.ml@gmail.com> wrote:
On 28/02/19 6:33 PM, Tim Mackinnon wrote:
So I would expect â1 to: 0â to see: 1 -> 1 2 -> 0.
It is difficult for code to guess the intent of the coder. Did the coder intend an decreasing sequence or a stopping condition (i == end or i > end?). Perhaps, we could use an explicit selector:
5 downto: 1
to disambiguate between the two cases.
Regards .. Subbu
On 1 Mar 2019, at 12:22, Tim Mackinnon <tim@testit.works> wrote:
Actually thats quite a good suggestion - it probably should have been:
#upTo: #downTo: #to:by:
In the first place (but Iâm guessing this change will never happen)
I like this too. Why would this not happen ? It is just one selector more. I think the only possible issue is that #to:do: is known by the compiler, which makes it faster than any other iteration, even do: - there is always a tradeoff between readability and raw speed.
On 1 Mar 2019, at 05:35, K K Subbu <kksubbu.ml@gmail.com> wrote:
On 28/02/19 6:33 PM, Tim Mackinnon wrote:
So I would expect â1 to: 0â to see: 1 -> 1 2 -> 0.
It is difficult for code to guess the intent of the coder. Did the coder intend an decreasing sequence or a stopping condition (i == end or i > end?). Perhaps, we could use an explicit selector:
5 downto: 1
to disambiguate between the two cases.
Regards .. Subbu
On 01/03/19 5:35 PM, Sven Van Caekenberghe wrote:
I like this too.
Why would this not happen ? It is just one selector more.
I think the only possible issue is that #to:do: is known by the compiler, which makes it faster than any other iteration, even do: - there is always a tradeoff between readability and raw speed.
Thank you for the kind words. I am not sure if speed would be affected much by: downTo: stop ^self to: stop by: -1 downTo: stop do: aBlock ^self to: stop by: -1 do: aBlock In performance critical paths, one can always use to:do: with explicit steps. Regards .. Subbu
Hey - sometimes these more philosophical conversations do amount to something. I will propose to gene changes and submit a pr - as after all, Pharo is ours and pointing someone to #downTo: or #upTo: would be very rewarding (and for Richard - #to: would remain the same so everyone wins) Tim Sent from my iPhone Sent from my iPhone
On 1 Mar 2019, at 18:30, K K Subbu <kksubbu.ml@gmail.com> wrote:
On 01/03/19 5:35 PM, Sven Van Caekenberghe wrote: I like this too. Why would this not happen ? It is just one selector more. I think the only possible issue is that #to:do: is known by the compiler, which makes it faster than any other iteration, even do: - there is always a tradeoff between readability and raw speed.
Thank you for the kind words. I am not sure if speed would be affected much by:
downTo: stop ^self to: stop by: -1
downTo: stop do: aBlock ^self to: stop by: -1 do: aBlock
In performance critical paths, one can always use to:do: with explicit steps.
Regards .. Subbu
participants (6)
-
K K Subbu -
Konrad Hinsen -
Offray Vladimir Luna Cárdenas -
Richard O'Keefe -
Sven Van Caekenberghe -
Tim Mackinnon