More powerful foreach statements

Oskar Linde oskar.lindeREM at OVEgmail.com
Fri Jul 21 08:15:00 PDT 2006


Andrei Khropov wrote:
> Oskar Linde wrote:
> 
>> Python style ranges:
>>
>> foreach(x; range(5))
>> 	... x is 0,1,2,3,4
>> foreach(x; range(1, 6))
>> 	... x is 1,2,3,4,5
>> foreach(x; range(1.5, 0, -0.25)) // bad idea to support doubles?
>> 	... x is 1.5, 1.25, 1.0, 0.75, 0.5, 0.25
> 
> Mmm, I would like slices to be first-class types and some synactic sugar:
> 
> -------------------------------------------------------
> foreach(i; 0..5)
> 	... i is 0,1,2,3,4
> 
> 
> slice   a   = 1..5;
> int[5]  arr = 0..5; // same as [0,1,2,3,4]
> 
> foreach(x; arr[a])
> 	... x is arr[1], arr[2], ...   arr[4]
> -------------------------------------------------------
> 
> But it's for D 1.0+ I think.

Yes. A slice type would be extremely nice, and would also be needed to 
support slicing of user defined multidimensional arrays.

I would love to see

opSlice(int start, int end)

replaced with:

opIndex(Range r);

which would allow multidimensional mixed indexing and slicing like:

arr[a..b, c, d..e, f..g, h, i];

via some template hackery. This could be implemented without breaking 
existing code by only calling opIndex(Range r) if no opSlice exists, so 
there is no rush to get this before D 1.0.

>> I've not found a good iterator design yet though. Only supporting foreach
>> style iteration is a bit too limited.
>>
>> I would also like array views to work as iterators and also support common
>> array operations without having to generate temporary arrays.
> 
> Yes, this is a definitely needed functionality.
> 
>> Currently:
>>
>> double pensionCosts = employees
>>          .filter((Employee e) { return e.age >= 28; })
>>          .map((Employee e) { return e.salary * 0.04; })
>>          .sum();
>>
>> Will generate a temporary Employee[] array and a temporary double[] array.
>>
>> Using array views one could get around the temporaries:
>>
>> // give all employees over 55 a 3 % raise:
>>
>> employees.select((Employee e) { return e.age >= 55; })
>>          .update((Employee e) { e.salary *= 1.03; });
>>
>> //(No temporaries created.)
>>
>> /Oskar
> 
> Such things should naturally belong to DTL I think.

Yeah. It's a pity D is so UDT hostile.

> And I would also like to see type inference for delegate params by argument
> type in parameter declaration, e.g. :
> 
> -------------------------------------------------------
> employees.select( (e) { return e.age >= 55; })
>          .update( (e) { e.salary *= 1.03; });
> -------------------------------------------------------
> 
> e is inferred to be Employee in both cases because select and update are
> declared as
> -------------------------------------------------------
> ... select( delegate bool(Employee e) )
> ... update( delegate void(Employee e) )
> -------------------------------------------------------
> 
> if select is overloaded with different types then this would be ambiguous of
> course and we have to explicitly specify arg type.

Yes, This makes D's delegates very close to Ruby's:
{|e| e.salary = e.salary * 1.03 }.
Exactly the same process of type inference exists already with foreach:

foreach(x; myObj)
// typeof(x) is inferred from the argument type of myObj.opApply()

/Oskar



More information about the Digitalmars-d mailing list