Foreach Range Statement
Don Clugston
dac at nospam.com.au
Tue Jul 24 00:07:56 PDT 2007
Bill Baxter wrote:
> Don Clugston wrote:
>> Bill Baxter wrote:
>>> Don Clugston wrote:
>>>> Reiner Pope wrote:
>>>>> Bill Baxter wrote:
>>>>>> Jarrett Billingsley wrote:
>>>>>>> "Xinok" <xnknet at gmail.com> wrote in message
>>>>>>> news:f80qof$2n0l$1 at digitalmars.com...
>>>>>>>
>>>>>>>> foreach(i; 0..100)
>>>>>>>
>>>>>>> This is almost identical to the syntax in MiniD:
>>>>>>>
>>>>>>> for(i: 0 .. 100)
>>>>>>>
>>>>>>> It could be done with for or foreach; I just chose for because
>>>>>>> normally you use for loops to iterate over ranges of integers.
>>>>>>>
>>>>>>> You can also come up with a pretty simple short-term solution
>>>>>>> that'll be fairly efficient (though not as efficient as if the
>>>>>>> compiler were aware of this kind of loop intrinsically) by making
>>>>>>> a struct 'range' which has a static opCall to construct a range
>>>>>>> and an opApply to iterate over the values, so that it'd look like:
>>>>>>>
>>>>>>> foreach(i; range(100))
>>>>>>>
>>>>>>> Which isn't terrible at all.
>>>>>>
>>>>>> And it has the advantage of being more extensible. And for
>>>>>> allowing ranges to be treated as first class entities that can be
>>>>>> passed around and manipulated. But no, instead we get another
>>>>>> one-trick pony.
>>>>>>
>>>>>> --bb
>>>>> That was my first thought, too.
>>>>>
>>>>> In the "Array Slice Ranges" thread, several people mentioned
>>>>> first-class ranges:
>>>>>
>>>>> http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=43865
>>>>>
>>>>> http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=43904
>>>>>
>>>>> http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=43905
>>>>>
>>>>> http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=43954
>>>>>
>>>>>
>>>>> Your implementation, Bill, seems to be just right, and gives you
>>>>> foreach over ranges for free.
>>>>>
>>>>> What's wrong with adding that to the language, but templated and
>>>>> with nice syntax?
>>>>>
>>>>> type name literal
>>>>> int..int (range of int) 1..5
>>>>> int..double (range of int to double) 1..5.0
>>>>> int..int:int (stepped range) 5..1:-1
>>>>>
>>>>> (I'm not sure of the use of mixed-type ranges, but this seems the
>>>>> most intuitive syntax. Since most ranges are probably of one type,
>>>>> how about allowing a symbol to denote "same type again". Any of the
>>>>> following could mean int..int: int..#, int.._, int..$)
>>>>
>>>> I don't think it make sense to have mixed type ranges. The normal
>>>> promotion rules should apply. However...
>>>>
>>>> Floating-point ranges are tricky. Should they be open-ended, or
>>>> closed-ended?
>>>
>>> Both Matlab and Numpy have floating point ranges. Matlab ranges are
>>> always inclusive, so 1:2.1:7.3 gives you 1.0, 3.1, 5.2, 7.3. Python
>>> ranges are always non-inclusive, so it gives you 1.0,3.1,5.2.
>>>
>>>> Consider
>>>> -real.infinity..real.infinity
>>>> Are the infinities part of the range? If not, how do you specify a
>>>> range which includes infinity?
>>>
>>> Does it matter that much? I suppose it would be cool if it did
>>> something really consistent, but Numpy just craps out and gives you
>>> an empty list, and Matlab raises an error "Maximum variable size
>>> allowed by the program is exceeded".
>>
>> I think that if you can't specify a range including an infinity, then
>> floating point ranges don't make sense. Especially, I really don't
>> like the idea that -real.infinity..real.infinity would include
>> -infinity, but not +infinity.
> > I've had a use for floating-point ranges: specifying domain and range of
> > functions, where infinity is fairly common. When else would you use
> them?
> >
>
> It sounds like maybe you're talking about "intervals" rather than
> "ranges". Yes, definitely intervals should be able to handle infinities
> correctly. But a range (a la python or matlab) is a shortcut for a
> sequence of values, with equal-size steps in between beginning and end.
OK, that makes sense. Although, for the integer case it's clear how many
elements are in a range; it's not at all obvious for floating point.
> To have the beginning or end be infinite is asking for trouble. For
> instance in Matlab that tries to allocate an infinite-sized array of
> numbers.
Agreed. Although 0..infinity is only one element bigger than 0..real.max.
>
>> Besides, "first_element .. last_element-1" doesn't work for (say)
>> 0.00001 .. 0.00003;
>
> Sure it does. It's just a set containing only 0.00001. I don't know
> what you mean by -1 there.
I mean, in the floating point case, you can't work out the last element of the
range by subtracting 1 from it.
>> But we probably don't want 1.0..5.0 to contain 5.0 when 1..5 doesn't
>> contain 5.
>
> Right. Numpy had the same problem. Python itself uses the same
> non-inclusive rule as D. But Python only handles integers in things like
> the "range(start,end,step)" function. The Numpy folks wanted to extend
> that to work for floating point types as well. But actually, in both
> matlab and numpy, if you want an evenly spaced set of numbers, you
> usually use the 'linspace' function, which has the signature
> linspace(begin,end,numvals). This creates an inclusive array of numbers.
That makes sense. You could also have a logarithmic range.
But what need is there for using ".." with floating point numbers? Surely we can
already write
foreach(float x, linspace(begin, end, numvals)){}
> I think one source of confusion is that ranges and slices are very
> similar things, but not quite the same.
>
> * A range is just a sequence of numbers. It can exist and be
> interpreted independently. Here allowing floating point numbers makes
> sense. Allowing for infinity may make sense, but practically it's very
> niche. Iterating over infinite things usually takes either too much
> time or too much memory.
How is that different to a set? I've always assumed a range (a,b) contained
EVERYTHING between a and b. I'm not very familiar with either Python or Matlab.
> * A slice needs an object to operate on for interpretation of
> object-relative things like $. Generally speaking, only integers make
> sense in a slice. Infinity doesn't really make sense because you can't
> generally have things that are both slice-able and infinite on a computer.
>
> (* An interval just represents two points on a numberline, plus maybe an
> indication of the inclusivity of the endpoints. Infinity -- ok.
> Floating point -- ok.)
>
> It may be possible to combine the concepts into one type, but they *are*
> slightly different, and may benefit from being treated as so.
That clarification is very helpful. Thanks.
More information about the Digitalmars-d
mailing list