Foreach Range Statement

Bill Baxter dnewsgroup at billbaxter.com
Mon Jul 23 14:00:10 PDT 2007


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. 
  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.

> 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.  Just think of it as a do-while loop that 
generates numbers:

begin..end:step basically generates this:
float[] a;
float v=begin;
do {
    a ~= v;
    v+=step;
} while(v<end);

> it has to be first_element..nextDown(lastElement).
> The MatLab method (closed ranges) is a nicer fit to IEEE arithmetic.
> In fact, I'd even say that half-open ranges are only ideal for unsigned 
> numbers.
> 
> 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.

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.

* 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.

--bb



More information about the Digitalmars-d mailing list