Jump to page: 1 24  
Page
Thread overview
Automatic Foreach
Apr 27, 2008
janderson
Apr 27, 2008
Janice Caron
Apr 27, 2008
Bill Baxter
Apr 27, 2008
janderson
Apr 27, 2008
Koroskin Denis
Apr 27, 2008
Bill Baxter
Apr 27, 2008
janderson
Apr 27, 2008
janderson
Apr 27, 2008
janderson
Apr 27, 2008
Bill Baxter
Apr 27, 2008
janderson
Apr 27, 2008
Bill Baxter
Apr 27, 2008
janderson
Apr 27, 2008
Janice Caron
Apr 27, 2008
Janice Caron
Apr 27, 2008
janderson
Apr 27, 2008
Janice Caron
Apr 27, 2008
e-t172
Apr 27, 2008
janderson
Apr 27, 2008
Janice Caron
Apr 27, 2008
Janice Caron
Apr 27, 2008
Knud Soerensen
Apr 27, 2008
Edward Diener
Apr 27, 2008
BCS
Apr 28, 2008
janderson
Apr 29, 2008
Bruno Medeiros
Apr 30, 2008
janderson
Apr 28, 2008
Jarrod
Apr 28, 2008
Bill Baxter
Apr 29, 2008
Bruno Medeiros
SwapStrategy issues again...
Apr 29, 2008
Brian Myers
Apr 29, 2008
Brian Myers
April 27, 2008
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?
April 27, 2008
Something at the back of my mind tells me that, once upon a time, Walter may have planned something like that for D, whereby

    a[] = n;
    a[] = b[];
    a[] = b[] + c[];
    a[] = f(b[]);

would mean

    foreach(ref e;a) e = n;
    foreach(i,ref e;a) e = b[i];
    foreach(i,ref e;a) e = b[i] + c[i];
    foreach(i,ref e;a) e = f(b[i]);

respectively. But if so, the plan got dropped a long time ago, and now only the first two cases work.

(Disclaimer: I may have got that completely wrong).

I don't see the problem with the foreach version though. It's certainly transparent.
April 27, 2008
On Sun, 27 Apr 2008 10:45:36 +0400, janderson <askme@me.com> wrote:
>
> //////////////////////////////////////////////////
> //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);
>    }
> }
>

Did you mean dot(val1, val2); here?
IMO, it saves you a little of typing, but you loose control over code execution.
It is hard to debug, it adds additional ambiguity.

f(char[] s);
f(char c);

char[] chars;
f(chars); // f(char[] s) is called, but I need foreach(), what should I do?

It is easy to write a template, that would do what you want:

template ReturnType(CallableType, TList...)
{
    CallableType c;
    TList u;
    static if (is(typeof(c(u)) == void)) {
        alias void Value;
    } else {
        alias typeof(c(u))[] Value;
    }
}

template auto_foreach(CallableType, ElementType)
{
    ReturnType!(CallableType,ElementType).Value auto_foreach(CallableType callable, ElementType[] elements)
    {
        alias ReturnType!(CallableType,ElementType).Value Type;
        static if (is(Type == void)) {
            foreach(e; elements) {
                callable(e);
            }
        } else {
            Type result;
            result.length = elements.length;
            int i = 0;
            foreach (e; elements) {
                result[i++] = callable(e);
            }
            return result;
        }
    }
}

void putc(char c)
{
    printf("%c", c);
}

char shift(char c)
{
    return c+1;
}

int main(string[] args)
{
    char[] h = "hello";
    h = auto_foreach(&shift, h);
    auto_foreach(&putc, h);

    return 0;
}

You could also change this template to accept multiple arrays as input. It's easy (use variadic template + recursion).
Make more practice in generic programming, it is worth it!
April 27, 2008
Janice Caron wrote:
> Something at the back of my mind tells me 

Maybe its the compiler error message that says "vector operations are not implemented" that's telling you that.  :-)  (as opposed to just plain "syntax error")

> that, once upon a time,
> Walter may have planned something like that for D, whereby
> 
>     a[] = n;
>     a[] = b[];
>     a[] = b[] + c[];
>     a[] = f(b[]);
> 
> would mean
> 
>     foreach(ref e;a) e = n;
>     foreach(i,ref e;a) e = b[i];
>     foreach(i,ref e;a) e = b[i] + c[i];
>     foreach(i,ref e;a) e = f(b[i]);
> 
> respectively. But if so, the plan got dropped a long time ago, and now
> only the first two cases work.
> 
> (Disclaimer: I may have got that completely wrong).
> 
> I don't see the problem with the foreach version though. It's
> certainly transparent.
April 27, 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
April 27, 2008
Janice Caron wrote:
> Something at the back of my mind tells me that, once upon a time,
> Walter may have planned something like that for D, whereby
> 
>     a[] = n;
>     a[] = b[];
>     a[] = b[] + c[];
>     a[] = f(b[]);
> 
> would mean
> 
>     foreach(ref e;a) e = n;
>     foreach(i,ref e;a) e = b[i];
>     foreach(i,ref e;a) e = b[i] + c[i];
>     foreach(i,ref e;a) e = f(b[i]);
> 
> respectively. But if so, the plan got dropped a long time ago, and now
> only the first two cases work.
> 
> (Disclaimer: I may have got that completely wrong).
> 
> I don't see the problem with the foreach version though. It's
> certainly transparent.

This raises an interesting point.  So the typesaftly issue could be solved like:

foo(array[]);

-Joel
April 27, 2008
Bill Baxter wrote:
> janderson wrote:
>> 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

I think I prefer:

foo(array[]);

-Joel
April 27, 2008
janderson wrote:
> Bill Baxter wrote:
>> janderson wrote:
>>> 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
> 
> I think I prefer:
> 
> foo(array[]);
> 
> -Joel


That could work with member functions too:

array[].foo();

-Joel
April 27, 2008
janderson wrote:
> janderson wrote:
>> Bill Baxter wrote:
>>> janderson wrote:
>>>> 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
>>
>> I think I prefer:
>>
>> foo(array[]);
>>
>> -Joel
> 
> 
> That could work with member functions too:
> 
> array[].foo();
> 
> -Joel

And slices:

array[0..5].foo();

-Joel
April 27, 2008
janderson wrote:
> Bill Baxter wrote:
>> janderson wrote:
>>> 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
> 
> I think I prefer:
> 
> foo(array[]);

I think that already means call foo with a full slice of array, doesn't it?  Anyway, even if it doesn't you can overload opSlice() currently so that array[] can mean anything you want it to.

--bb
« First   ‹ Prev
1 2 3 4