More powerful foreach statements

Oskar Linde oskar.lindeREM at OVEgmail.com
Fri Jul 21 10:01:04 PDT 2006


pragma wrote:
> In article <e9qe1i$1m5c$3 at digitaldaemon.com>, Oskar Linde says...
>> 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.
>>
>> 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
> 
> IMO, I think it's all *very* worth it.  It kind of fills this gap between what
> phobos gives us and what STL's iterators and algorithms has to offer. 
> 
> I think that if you have an 'array view' widget/template that supports
> opApply(), length(), and opIndex() for all the view types you return, then
> you're pretty much set.  That will cover both the random-access and
> sequential-access modes that arrays already enjoy.  That way, you can support
> for() iteration as well, and still not need any temporaries. ;)

Yes, that is probably the right way do to it. If the views support the 
same operations as arrays do, they will be usable just as arrays, and 
views-of-views and similar would work transparently.

> As for ranges, I wouldn't throw those out.  Ruby also has them, and thanks to
> Rails, prototype.js now supports them now too.  I'd be willing to bet that
> someone will come along to the DNG and say "Where's the range support?!" - and
> we can all just point them to your library.  
> 
> I'd imagine ranges being an extension of your 'array view' concept.

Yes, ideally, a range should work just like a (read only) array, but 
without allocating any memory. Silly example:

range(100).select((int x) { return x % 5 == 0 }).sum()
//returns 950

> I think something like the following would be workable:
> 
> /**/ struct ReverseArrayView(ArrayT){
> /**/   ElemType!(ArrayT) opIndex(uint idx);
> /**/   ArrayT opSlice(uint start,uint end); //creates temporary or another view?
> /**/   int opApply(int delegate(inout ElemType!(ArrayT)) dg);
> /**/   uint length();
> /**/   static opCall(ArrayT arr);
> /**/ }
> /**/
> /**/ template reverse(ArrayT){
> /**/   ReverseArrayView!(ArrayT) reverse(ArrayT arr){ 
> /**/     return ReverseArrayView!(ArrayT)(arr);
> /**/   }
> /**/ }
> 
> The trick is to get ArrayView instances to jive with your templates like
> ElemType!() such that they get treated like first-class arrays where possible. I
> think static if() could be used to check for a static property on ArrayViews
> like "isArrayView=true", such that standard arrays will fail the test.

Yes, that is definitely doable. The only problem is that there is no way 
to "inject" methods for anything but built-in arrays. I'd have to add 
wrappers to all views for all functions (a mixin will probably be 
enough), or live with calling them as ordinary functions:

update(select(employees,
              (Employee e) { return e.age >= 55; }),
       (Employee e) { e.salary *= 1.03; });

instead of:

employees.select((Employee e) { return e.age >= 55; })
          .update((Employee e) { e.salary *= 1.03; });

It would be nice to have a way to inject methods/define extension 
methods for other types than arrays. Maybe something like what has been 
proposed before:

int squared(this int x) { return x*x; }
and called:
5.squared();

Just add ifti template support to this and the array functions would be 
applicable as methods of any type that implements the needed iterator 
semantics (opApply or opIndex and length()).

/Oskar



More information about the Digitalmars-d mailing list