www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Automatic Foreach

reply janderson <askme me.com> writes:
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?
Apr 26 2008
next sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
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.
Apr 27 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
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.
Apr 27 2008
prev sibling parent janderson <askme me.com> writes:
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
Apr 27 2008
prev sibling next sibling parent "Koroskin Denis" <2korden gmail.com> writes:
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 =3D dot(array1, array2);

 Equivalent too:

 vector[] vertex;
 vector.length =3D array1.length * array2.length;
 int i=3D0;
 foreach (auto val1; array1)
 {
    foreach (auto val2; array2)
    {
      vertex[i++] =3D 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)) =3D=3D void)) { alias void Value; } else { alias typeof(c(u))[] Value; } } template auto_foreach(CallableType, ElementType) { ReturnType!(CallableType,ElementType).Value auto_foreach(CallableTy= pe = callable, ElementType[] elements) { alias ReturnType!(CallableType,ElementType).Value Type; static if (is(Type =3D=3D void)) { foreach(e; elements) { callable(e); } } else { Type result; result.length =3D elements.length; int i =3D 0; foreach (e; elements) { result[i++] =3D callable(e); } return result; } } } void putc(char c) { printf("%c", c); } char shift(char c) { return c+1; } int main(string[] args) { char[] h =3D "hello"; h =3D 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!
Apr 27 2008
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Apr 27 2008
parent reply janderson <askme me.com> writes:
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
Apr 27 2008
next sibling parent reply janderson <askme me.com> writes:
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
Apr 27 2008
parent janderson <askme me.com> writes:
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
Apr 27 2008
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Apr 27 2008
parent reply janderson <askme me.com> writes:
Bill Baxter 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[]);
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
That's the point though. If there's already an overload available then that should be used. It allows you to come along later and write specialized behavior. -Joel
Apr 27 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
janderson wrote:
 Bill Baxter 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[]);
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
That's the point though. If there's already an overload available then that should be used. It allows you to come along later and write specialized behavior.
Ok I suppose. As long as you're aware what your proposing will break existing code, which means the barrier for accepting the proposal will be a lot higher. --bb
Apr 27 2008
parent reply janderson <askme me.com> writes:
Bill Baxter wrote:
 janderson wrote:
 Bill Baxter 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[]);
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
That's the point though. If there's already an overload available then that should be used. It allows you to come along later and write specialized behavior.
Ok I suppose. As long as you're aware what your proposing will break existing code, which means the barrier for accepting the proposal will be a lot higher. --bb
How?
Apr 27 2008
next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 27/04/2008, janderson <askme me.com> wrote:
 Ok I suppose.  As long as you're aware what your proposing will break
existing code, which means the barrier for accepting the proposal will be a lot higher. How?
auto a = array1[] ~ array2[];
Apr 27 2008
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
Actually, I should have said that, in general, Joel's proposal is
undefined for all non-unary operations.

   a[] = b[] + c[]

   f(a[], b[], c[], d[])

etc.
Apr 27 2008
parent reply janderson <askme me.com> writes:
Janice Caron wrote:
 Actually, I should have said that, in general, Joel's proposal is
 undefined for all non-unary operations.
 
    a[] = b[] + c[]
 
    f(a[], b[], c[], d[])
 
 etc.
My proposal was to generate nested loops and base it of the order the arrays where specified. However it could just as easily be parallel for all values and require that all arrays are the same size. -Joel
Apr 27 2008
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 27/04/2008, janderson <askme me.com> wrote:
 Janice Caron wrote:

 Actually, I should have said that, in general, Joel's proposal is
 undefined for all non-unary operations.

   a[] = b[] + c[]

   f(a[], b[], c[], d[])
My proposal was to generate nested loops and base it of the order the arrays where specified. However it could just as easily be parallel for all values and require that all arrays are the same size.
I think I'd be happy with a template in std.algorithm. // a[] = b[] + c[] auto a = parallel!("a = b + c")(a,b,c); // foo(array1[], array2[], array3[], array4[]) parallel!("foo(a,b,c,d)")(array1,array2,array3,array4); Or some such. I'm sure Andrei could write that. He's a clever guy.
Apr 27 2008
next sibling parent e-t172 <e-t172 akegroup.org> writes:
Janice Caron a écrit :
 I think I'd be happy with a template in std.algorithm.
 
     // a[] = b[] + c[]
     auto a = parallel!("a = b + c")(a,b,c);
 
     // foo(array1[], array2[], array3[], array4[])
     parallel!("foo(a,b,c,d)")(array1,array2,array3,array4);
 
 Or some such. I'm sure Andrei could write that. He's a clever guy.
Basically, that would be an equivalent of the "map" function present in functional programming languages.
Apr 27 2008
prev sibling parent janderson <askme me.com> writes:
Janice Caron wrote:
 On 27/04/2008, janderson <askme me.com> wrote:
 Janice Caron wrote:

 Actually, I should have said that, in general, Joel's proposal is
 undefined for all non-unary operations.

   a[] = b[] + c[]

   f(a[], b[], c[], d[])
My proposal was to generate nested loops and base it of the order the arrays where specified. However it could just as easily be parallel for all values and require that all arrays are the same size.
I think I'd be happy with a template in std.algorithm. // a[] = b[] + c[] auto a = parallel!("a = b + c")(a,b,c); // foo(array1[], array2[], array3[], array4[]) parallel!("foo(a,b,c,d)")(array1,array2,array3,array4); Or some such. I'm sure Andrei could write that. He's a clever guy.
I don't know. Might as well use a foreach if its going to start looking like that. -Joel
Apr 27 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 27/04/2008, janderson <askme me.com> wrote:
  I think I prefer:

  foo(array[]);
The problem is that [] already has a defined meaning. struct S { R opSlice() { ... } } S array; foo(array[]); should call foo(array.opSlice()); so then you'd have to do foo(array[][]); to disambiguate. Personally, I see absolutely no use for the /existing/ use of [], whereby array[] means array[0..$]. I won't feel a moment's pang of regret if this usage were dropped. That would free up [] to be redeployed for "vector operations".
Apr 27 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 27/04/2008, janderson <askme me.com> wrote:
  I think I prefer:

  foo(array[]);
Your suggestion would still ambiguous even if [] were redeployed. Bill's wouldn't. Consider f(a[]) + g(b[]) Do we mean f([x foreach(x:a)]) + g([y foreach(y:b)]) or [f(x) + g(b[i]) foreach(i,x:a)] ? I have to say, I prefer a variation of Bill's syntax. I'd want foreach at the front, not at the back. Python tries to be more like natural language, but D wants to be more compiler-friendly (easy to parse). So I'd want [foreach(x:a) expr(x)]
Apr 27 2008
prev sibling next sibling parent Knud Soerensen <4tuu4k002 sneakemail.com> writes:
Have a look at the vectorization suggestion
http://all-technology.com/eigenpolls/dwishlist/index.php?it=10
on the wish list.
http://all-technology.com/eigenpolls/dwishlist/

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.
 
 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.
 
if you encapsulating the loop in the function you get 1 functions call and N loop-body executions but if you let d loop the function you get N function calls and N body excutions. You are adding N-1 extra function calls ! Knud
Apr 27 2008
prev sibling next sibling parent Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
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);
 }
foreach(auto value; array) { foo(value); }
 
 becomes:
 
 foo(array);
Apr 27 2008
prev sibling next sibling parent BCS <ao pathlink.com> writes:
Reply to janderson,
 
 float[] array;
 array ~= sqrt(array2);
how about char[] to; char[][] from; to ~= from; goes to uint add=0; foreach(a;from) add+=a.length; to.length += add; foreach(a;from) { to[$-add,$-add+a.length = a[] add-= a.length; } ??
Apr 27 2008
prev sibling next sibling parent reply janderson <askme me.com> writes:
I think people have missed the point on my suggestion.  I wanted 
something that I could use within a template (see example at bottom). 
Something that I could override later or use the overridden case (if 
someone had already written a function to handle arrays of that type).


I often write functions like:

int Covert(int a)
{
...
}


Then endup writing an array version as well.

int[] Convert(int[] a)
{
   int result[];
   result.length = a.length;
   int i=0;
   foreach( ; )
   {
     result [i++];

   }
}

80% of the time the array version is pretty much the same thing.  So a 
while back I wrote a template that works like:

void foo(int i)
{
   printf("B");
}

alias AutoForeach!(foo, int) foo;

Then I could go:

for(6); //Prints "B"
int[] array;
array = 2;
foo(array); //Prints "BB"

But then I couldn't specialize it later without removing the alias, 
because I'd get a name clash.

The other problem is this won't do cases like:

result ~= foo(array);

or

foo(foo1(array));  //Runs foo and foo1 array.length times.


It started cutting my code size down by about 30%.  So I thought it 
might be a good idea for the language.  The language would be able to 
provide provide the candy that you would never be able to get with 
templates.


//////////////////////////////////////////////////
//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.

So it's equivalent to:

foreach (auto val; array1)
{
   write(val);
}

foreach (auto val; array2)
{
   write(val);
}

write(value);
Apr 28 2008
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
janderson wrote:
 while back I wrote a template that works like:
 
 void foo(int i)
 {
   printf("B");
 }
 
 alias AutoForeach!(foo, int) foo;
 
 Then I could go:
 
 for(6); //Prints "B"
 int[] array;
 array = 2;
 foo(array); //Prints "BB"
 
 But then I couldn't specialize it later without removing the alias, 
 because I'd get a name clash.
 
 The other problem is this won't do cases like:
 
 result ~= foo(array);
 
Why not? Didn't you define AutoForeach!(foo, int) to return an int[] ?
 or
 
 foo(foo1(array));  //Runs foo and foo1 array.length times.
 
 
Same as above. -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 29 2008
parent janderson <askme me.com> writes:
Bruno Medeiros wrote:
 janderson wrote:
 while back I wrote a template that works like:

 void foo(int i)
 {
   printf("B");
 }

 alias AutoForeach!(foo, int) foo;

 Then I could go:

 for(6); //Prints "B"
 int[] array;
 array = 2;
 foo(array); //Prints "BB"

 But then I couldn't specialize it later without removing the alias, 
 because I'd get a name clash.

 The other problem is this won't do cases like:

 result ~= foo(array);
Why not? Didn't you define AutoForeach!(foo, int) to return an int[] ?
Your right a AutoForEachReturn could work here.
 
 or

 foo(foo1(array));  //Runs foo and foo1 array.length times.
I forgot to mention that in that example foo1 was defined with the autoforeach, foo was not (and it wouldn't work even if I did).
 
 Same as above.
 
Apr 29 2008
prev sibling next sibling parent terranium <spam here.lot> writes:
     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]);
 
This raises an interesting point. So the typesaftly issue could be solved like: foo(array[]);
This is better but still is too inobvious. How about making it a variant of foreach? foreach a[] = n; foreach a[] = b[]; foreach a[] = b[] + c[]; foreach a[] = f(b[]); foreach { a[] = f(b[]); d[]=b[]+c[]; }
Apr 28 2008
prev sibling next sibling parent terranium <spam here.lot> writes:
janderson Wrote:
 This raises an interesting point.
 
 -Joel
ps and I don't think an automatic resize to be a good idea.
Apr 28 2008
prev sibling next sibling parent terranium <spam here.lot> writes:
 Ok I suppose.  As long as you're aware what your proposing will break 
 existing code,  which means the barrier for accepting the proposal will 
 be a lot higher.
This is a problem :/ For what reason the entire slice exists for in fact? Does it have any meaning?
Apr 28 2008
prev sibling next sibling parent terranium <spam here.lot> writes:
Bill Baxter Wrote:
 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.
array.foo() also has an existing meaning of foo(array)
Apr 28 2008
prev sibling parent reply Jarrod <qwerty ytre.wq> writes:
 What do you think?
I think Walter really needs to get macros implemented in D. Then we could all make our own little specific loops, which is far more reasonable. Your idea is well demonstrated, but I don't like the syntax. It doesn't really tell you what is going on just by looking at it. PS: You also might want to look at 'map' in phobos2's std.algorithm.
Apr 28 2008
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Jarrod wrote:
 What do you think?
I think Walter really needs to get macros implemented in D. Then we could all make our own little specific loops, which is far more reasonable. Your idea is well demonstrated, but I don't like the syntax. It doesn't really tell you what is going on just by looking at it. PS: You also might want to look at 'map' in phobos2's std.algorithm.
Python has map() too, but people prefer to use list comprehensions for some reason. --bb
Apr 28 2008
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 Jarrod wrote:
 What do you think?
I think Walter really needs to get macros implemented in D. Then we could all make our own little specific loops, which is far more reasonable. Your idea is well demonstrated, but I don't like the syntax. It doesn't really tell you what is going on just by looking at it. PS: You also might want to look at 'map' in phobos2's std.algorithm.
Python has map() too, but people prefer to use list comprehensions for some reason. --bb
Comprehensions might be syntactically nicer than map, but as for the original proposal (automatic foreach), the map construct covers it quite nicely and sufficiently. -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 29 2008
parent reply Brian Myers <bmyers harryanddavid.com> writes:
I'm getting the following error messages now. Does SwapStrategy have to be
specified at compile time?

C:\Documents and Settings\dag033\D\d_dedup>dmd -g d_dedup.d
..\d_libcsv\d_libcsv.d ..\d_libcsv\csv.d ..\d_libcsv\bin\deb
ug\d_libcsv.lib
c:\dmd\bin\..\src\phobos\std\algorithm.d(2632): Error: expression ss ==
cast(SwapStrategy)0 is not constant or does not
evaluate to a bool
c:\dmd\bin\..\src\phobos\std\algorithm.d(2655): static assert  (ss !=
cast(SwapStrategy)1) is not evaluatable at compile
 time

Here's the call to schwartzSort!:

protected:
    SwapStrategy ss;
.
.
.
schwartzSort!(kx.get_key, "a < b", ss)(lines);

Thanx

Brian
Apr 29 2008
parent Brian Myers <bmyers harryanddavid.com> writes:
Argh, sorry, meant this to be a new topic post. I'll try again.

Brian Myers Wrote:

 I'm getting the following error messages now. Does SwapStrategy have to be
specified at compile time?
 
 C:\Documents and Settings\dag033\D\d_dedup>dmd -g d_dedup.d
..\d_libcsv\d_libcsv.d ..\d_libcsv\csv.d ..\d_libcsv\bin\deb
 ug\d_libcsv.lib
 c:\dmd\bin\..\src\phobos\std\algorithm.d(2632): Error: expression ss ==
cast(SwapStrategy)0 is not constant or does not
 evaluate to a bool
 c:\dmd\bin\..\src\phobos\std\algorithm.d(2655): static assert  (ss !=
cast(SwapStrategy)1) is not evaluatable at compile
  time
 
 Here's the call to schwartzSort!:
 
 protected:
     SwapStrategy ss;
 .
 .
 .
 schwartzSort!(kx.get_key, "a < b", ss)(lines);
 
 Thanx
 
 Brian
 
Apr 29 2008