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