Automatic Foreach

Bill Baxter dnewsgroup at billbaxter.com
Sun Apr 27 01:17:20 PDT 2008


janderson wrote:
> I know Walter has his head stuck in Const/Invarient/Pure multithreading 
> land at the moment.  I thought I'd fire off this interesting proposal 
> anyway.
> 
> This is a follow up proposal/suggestion to one I sent a while back.  I 
> hope to flesh it out a bit more.
> 
> The idea is to automatically generate for loops for arrays that are used 
> as parameters.  It will reduces type safety in one area but makes the 
> language more expressive, particularly for templates.
> 
> Basically:
> 
> void foo(char c)
> {
>  ...
> }
> 
> ...
> 
> char[] array;
> 
> ...
> 
> This part:
> 
> foreach(auto value; array)
> {
>   foo(array);
> }
> 
> becomes:
> 
> foo(array);
> 
> 
> More advanced stuff:
> 
> //////////////////////////////////////////////////
> //Example 1
> //////////////////////////////////////////////////
> // The return value is called multiple times:
> 
> float[] array;
> array ~= sqrt(array2);
> 
> Where sqrt is:
> 
> float sqrt(float value);
> 
> Would be equivalent to:
> 
> int i = array.length;
> array.length += array2.length;
> foreach(auto val; array2)
> {
>   array[i++] = sqrt(val);
> }
> 
> //////////////////////////////////////////////////
> //Example 2
> //////////////////////////////////////////////////
> // When assigned to an array, that array should automatically be resized 
> to the number of iterations the function is be called.
> 
> float[] array = sqrt(array2);  //array is resized to the correct size
> 
> Would be equivalent to:
> 
> float[] array;
> array.length = array2.length;
> int i = 0;
> foreach(auto val; array2)
> {
>   array[i++] = sqrt(val);
> }
> 
> //////////////////////////////////////////////////
> //Example 3
> //////////////////////////////////////////////////
> // Multiple array inputs should work like nested arrays.
> 
> vector[] vertex = dot(array1, array2);
> 
> Equivalent too:
> 
> vector[] vertex;
> vector.length = array1.length * array2.length;
> int i=0;
> foreach (auto val1; array1)
> {
>   foreach (auto val2; array2)
>   {
>     vertex[i++] = sqrt(val1, val2);
>   }
> }
> 
> //////////////////////////////////////////////////
> //Example Member functions
> //////////////////////////////////////////////////
> // This is potentially less useful and could be made illegal.  I'll 
> mention it for completeness.
> 
> class A
> {
>   void foo();
> }
> 
> ...
> 
> A[] a;
> 
> ...
> 
> a.foo();  //Call foo for the length of a
> 
> 
> Equivalent to:
> 
> foreach (auto val; a)
> {
>    a.foo();
> }
> 
> //////////////////////////////////////////////////
> //Example Return types
> //////////////////////////////////////////////////
> 
> proccess(array).foo().foo2();
> 
> Equivalent too:
> 
> foreach (auto val; )
> {
>   proccess(val).foo().foo2();
> }
> 
> //////////////////////////////////////////////////
> //Use example nested
> //////////////////////////////////////////////////
> 
> 
> results ~= func(foo(array1), foo2(array2));
> 
> Equivalent too:
> 
> results.length += array1.length * array2.length;
> int i = results.length;
> foreach (auto val1; array1)
> {
>   foreach (auto val2; array2)
>   {
>      results[i++] = func(foo(val1), foo2(val2));
>   }
> }
> 
> 
> //////////////////////////////////////////////////
> //Use example
> //////////////////////////////////////////////////
> 
> results ~= func(foo(array1)).method(array2);
> 
> results.length += array1.length * array2.length;
> int i = results.length;
> foreach (auto val1; array1)
> {
>   foreach (auto val2; array2)
>   {
>      results[i++] = func(foo(val1)).method(val2);
>   }
> }
> 
> //////////////////////////////////////////////////
> //Use example with templates
> //////////////////////////////////////////////////
> 
> void print(A ...)(A a)
> {
>   write(a);
> }
> 
> print(array1, array2, value);
> 
> //What happens here is the array is passed into the template, because an 
> array is a valid input into a template.  The value is only evaluated 
> when inside the template. See overloading rules below.
> 
> So it's equivalent to:
> 
> foreach (auto val; array1)
> {
>   write(val);
> }
> 
> foreach (auto val; array2)
> {
>   write(val);
> }
> 
> Overloading rules:
> 
> This auto foreach is given the lowest priority.  If there's already a 
> way to call the function then that will be used.  That will enable 
> people to specialize how arrays are handled for different functions be 
> overloading it.  Templates for example, an array is a valid input so it 
> won't call the template function multiple times.
> 
> Working with the future:
> The proposal should work well with features such as pure functions.  It 
> should be as optimal as foreach statements however the compiler would 
> have to do less work to realize optimizations.
> 
> Interchangeable methods/functions: If this feature comes in, I don't see 
> any problem with the proposal working.
> 
> Rantional:
> Half the time I create a for loop I endup encapsulating it in a 
> function.  If D automatically created the function it would be one less 
> thing to worry about.  If I need specialize behavior I could always 
> specialize the function later by providing an overload.
> 
> I think having this functionality would remove much of the need for 
> being able to iterate over 2 arrays at the same time.
> 
> Comment:
> I know python has syntax not unlike this, however I believe the above is 
> even simpler.
> 
> What do you think?

I think it's already hard enough to figure out what's going to get 
called by something like foo(array)

It could be
- foo(int[] x)
- foo(int[] x...)
- foo(T)(T x)
- foo(T)(T[] x)
- foo(T...)(T x)
- struct foo { static foo opCall(int[]); }
- struct foo { static foo opCall(int[]...); }
- struct foo { static foo opCall(T)(T x); }  etc
- or struct Foo with non-static opCall on instance foo
- or all the same stuff on class  ...

So I don't think another meaning for foo(array) is really helpful.

I *do* like the idea of an expression (not a statement) that has 
foreach-like abilities.  But I think it should come with some 
distinguishing syntax.

In Python it's just [expr(x) for x in array]
Which resonates with Pythons normal loopoing:
    for x in array: expr(x)

So direct translation of that idea to D would be
    [expr(x) foreach(x; array)];

Seems not so terrible a syntax to me.

--bb



More information about the Digitalmars-d mailing list