www.digitalmars.com         C & C++   DMDScript  

D - foreach ( foreach <- D ) { change syntax }

reply "Jeroen van Bemmel" <someone somewhere.com> writes:
Hi Walter,

I finally had the time to read your (and Matt's) article in DDJ on D's
foreach construct. I think it's well-written. I have three suggestions for
even more improvement (in my opinion) of the construct:

1) The syntax
Current syntax is "foreach( uint v; aa ) { ... }" (from the article), ie
first element is a variable declaration and the second is a variable
denoting some collection. My remark may be an itty bitty detail, but I don't
like the ';' in this. Normally ';' is used as statement separator, and in C
the for ( x ; y ; z ) syntax closely related to the notion that x,y,z are
statements that are put in a particular order (it's syntactic sugar for " x
; while (y) { .... z }"). "uint v" may be a statement (variable
declaration), but 'aa' isn't, at least not in itself. The semantics are that
'v' comes from the elements in 'aa', and I think this should be reflected in
the syntax.

Possible alternatives:
foreach( uint v from aa ) { ... }
foreach( uint v in aa ) { ... }
foreach( uint v <- aa ) { ... }
foreach( uint v : aa ) { ... }

"from" and "in" would mean additional keywords, which I don't like too much.
My personal preference is the last one using ':'

2) The type declaration
The type declaration in the foreach syntax is redundant, since it should
match the type of elements in the collection. I think the compiler should be
able to determine this somehow (this would require new syntax for collection
classes, similar to templates). Rather similar to the new type safe
collections in Java, which I like too.

3) The 'opApply' convention
Why not use 'foreach' as the method name? This reflects the context in which
the method is invoked, and also allows syntax such as "aa.foreach( f )"
which IMO is slightly more readable than "aa.opApply( f )"

JvB
Mar 04 2004
next sibling parent Matthias Becker <Matthias_member pathlink.com> writes:
1) The syntax
Current syntax is "foreach( uint v; aa ) { ... }" (from the article), ie
first element is a variable declaration and the second is a variable
denoting some collection. My remark may be an itty bitty detail, but I don't
like the ';' in this. Normally ';' is used as statement separator, and in C
the for ( x ; y ; z ) syntax closely related to the notion that x,y,z are
statements that are put in a particular order (it's syntactic sugar for " x
; while (y) { .... z }"). "uint v" may be a statement (variable
declaration), but 'aa' isn't, at least not in itself. The semantics are that
'v' comes from the elements in 'aa', and I think this should be reflected in
the syntax.

Possible alternatives:
foreach( uint v from aa ) { ... }
foreach( uint v in aa ) { ... }
foreach( uint v <- aa ) { ... }
foreach( uint v : aa ) { ... }

"from" and "in" would mean additional keywords, which I don't like too much.
My personal preference is the last one using ':'
in is a keyword. And in 'for ( x ; y ; z )' y is a statement? Nope. y is just like aa in your foreach example.
2) The type declaration
The type declaration in the foreach syntax is redundant, since it should
match the type of elements in the collection.
You forgot to explain, why it has to match. IMHO it doesn't have to.
Mar 05 2004
prev sibling next sibling parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
Jeroen van Bemmel wrote:

Hi Walter,

I finally had the time to read your (and Matt's) article in DDJ on D's
foreach construct. I think it's well-written. I have three suggestions for
even more improvement (in my opinion) of the construct:


2) The type declaration
The type declaration in the foreach syntax is redundant, since it should
match the type of elements in the collection. I think the compiler should be
able to determine this somehow (this would require new syntax for collection
classes, similar to templates). Rather similar to the new type safe
collections in Java, which I like too.
  
I like this suggestion (I suggested it before). The old syntax could be kept for situations where you need to spell out which opApply to use, but in other cases it's redundant. Almost everytime I use a foreach, I find myself having to look up the type. foreach (n; array) {} Would be a lot easier to remember. One thing I like about D is that in may cases it has removed the redundancies that exist in C++. The think I don't like is that D has brought in new redundancies by not having automatic type deduction. If automatic type deduction is so difficult to implement right, why can't we have a reduced-automatic type deduction. ie template Max(T) { T Max(T a, T b) { } } Instead of: Max!(int).Max(a,b); use: Max!!(a,b); would be equivalent to: Max!(typeof(a))(a,b); Note that there would two types, then the order of the would be important. ie template Foo(T, C) { void Foo(T a, C b) { } } Foo!!(a, b); Equivalent to: Foo!(typeof(a), typeof(b)).Foo(a,b); Anything difficult and the compiler could spit at the coder asking for an explicit definition. -- -Anderson: http://badmama.com.au/~anderson/
Mar 05 2004
parent reply Matthias Becker <Matthias_member pathlink.com> writes:
One thing I like about D is that in 
may cases it has removed the redundancies that exist in C++.  The think 
I don't like is that D has brought in new redundancies by not having 
automatic type deduction.  If automatic type deduction is so difficult 
to implement right, why can't we have a reduced-automatic type 
deduction.  ie

template Max(T)
{
   T Max(T a, T b) { }
} 

Instead of:
Max!(int).Max(a,b);

use:
Max!!(a,b);

would be equivalent to:
Max!(typeof(a))(a,b);

Note that there would two types, then the order of the would be 
important. ie

template Foo(T, C)
{
   void Foo(T a, C b) { }
}

Foo!!(a, b);

Equivalent to:
Foo!(typeof(a), typeof(b)).Foo(a,b);

Anything difficult and the compiler could spit at the coder asking for 
an explicit definition.
Have you read my proposal about adding "let"?
Mar 05 2004
parent J Anderson <REMOVEanderson badmama.com.au> writes:
Matthias Becker wrote:

One thing I like about D is that in 
may cases it has removed the redundancies that exist in C++.  The think 
I don't like is that D has brought in new redundancies by not having 
automatic type deduction.  If automatic type deduction is so difficult 
to implement right, why can't we have a reduced-automatic type 
deduction.  ie

template Max(T)
{
  T Max(T a, T b) { }
} 

Instead of:
Max!(int).Max(a,b);

use:
Max!!(a,b);

would be equivalent to:
Max!(typeof(a))(a,b);

Note that there would two types, then the order of the would be 
important. ie

template Foo(T, C)
{
  void Foo(T a, C b) { }
}

Foo!!(a, b);

Equivalent to:
Foo!(typeof(a), typeof(b)).Foo(a,b);

Anything difficult and the compiler could spit at the coder asking for 
an explicit definition.

    
Have you read my proposal about adding "let"?
Yeah, but it was a while back (and I couldn't find the original suggestion). I'm not sure if I liked it, didn't like it or didn't understand your proposal. -- -Anderson: http://badmama.com.au/~anderson/
Mar 05 2004
prev sibling parent reply "Ben Hinkle" <bhinkle4 juno.com> writes:
"Jeroen van Bemmel" <someone somewhere.com> wrote in message
news:c2989f$6a6$1 digitaldaemon.com...
| Hi Walter,
|
| I finally had the time to read your (and Matt's) article in DDJ on D's
| foreach construct. I think it's well-written. I have three suggestions for
| even more improvement (in my opinion) of the construct:
|
| 1) The syntax
| Current syntax is "foreach( uint v; aa ) { ... }" (from the article), ie
| first element is a variable declaration and the second is a variable
| denoting some collection. My remark may be an itty bitty detail, but I don't
| like the ';' in this. Normally ';' is used as statement separator, and in C
| the for ( x ; y ; z ) syntax closely related to the notion that x,y,z are
| statements that are put in a particular order (it's syntactic sugar for " x
| ; while (y) { .... z }"). "uint v" may be a statement (variable
| declaration), but 'aa' isn't, at least not in itself. The semantics are that
| 'v' comes from the elements in 'aa', and I think this should be reflected in
| the syntax.
|
| Possible alternatives:
| foreach( uint v from aa ) { ... }
| foreach( uint v in aa ) { ... }
| foreach( uint v <- aa ) { ... }
| foreach( uint v : aa ) { ... }
|
| "from" and "in" would mean additional keywords, which I don't like too much.
| My personal preference is the last one using ':'

The "foreach" syntax should parallel the "for" syntax:
 foreach(declaration-list ; expression) body
 for(declaration-list ; expression ; expression) body
The declaration-list is a comma separated list of looping variables. Seems
like a pretty natural extension of the "for" syntax.

| 2) The type declaration
| The type declaration in the foreach syntax is redundant, since it should
| match the type of elements in the collection. I think the compiler should be
| able to determine this somehow (this would require new syntax for collection
| classes, similar to templates). Rather similar to the new type safe
| collections in Java, which I like too.

Might be nice but if it is added here it would seem odd that foreach is
the only place declaration types get inferred. What about
void foo()
{
   x=1; // c'mon, D, you know what type I want ;-)
}
And someone else mentioned template instantiation. There's a can of worms
in them thar hills.

| 3) The 'opApply' convention
| Why not use 'foreach' as the method name? This reflects the context in which
| the method is invoked, and also allows syntax such as "aa.foreach( f )"
| which IMO is slightly more readable than "aa.opApply( f )"

That sounds very reasonable to me. Another problem I have with opApply is that
since overloading is fairly weak in D that an opApply meant for foreach could
interfere with an opApply meant for ... opApply and result in casts when they
shouldn't be needed. One problem with "foreach" is that it is a keyword and so
maybe something like "foreachApply" would be better.

|
| JvB
|
|
Mar 05 2004
next sibling parent reply Matthias Becker <Matthias_member pathlink.com> writes:
| Hi Walter,
|
| I finally had the time to read your (and Matt's) article in DDJ on D's
| foreach construct. I think it's well-written. I have three suggestions for
| even more improvement (in my opinion) of the construct:
|
| 1) The syntax
| Current syntax is "foreach( uint v; aa ) { ... }" (from the article), ie
| first element is a variable declaration and the second is a variable
| denoting some collection. My remark may be an itty bitty detail, but I don't
| like the ';' in this. Normally ';' is used as statement separator, and in C
| the for ( x ; y ; z ) syntax closely related to the notion that x,y,z are
| statements that are put in a particular order (it's syntactic sugar for " x
| ; while (y) { .... z }"). "uint v" may be a statement (variable
| declaration), but 'aa' isn't, at least not in itself. The semantics are that
| 'v' comes from the elements in 'aa', and I think this should be reflected in
| the syntax.
|
| Possible alternatives:
| foreach( uint v from aa ) { ... }
| foreach( uint v in aa ) { ... }
| foreach( uint v <- aa ) { ... }
| foreach( uint v : aa ) { ... }
|
| "from" and "in" would mean additional keywords, which I don't like too much.
| My personal preference is the last one using ':'

The "foreach" syntax should parallel the "for" syntax:
 foreach(declaration-list ; expression) body
 for(declaration-list ; expression ; expression) body
The declaration-list is a comma separated list of looping variables. Seems
like a pretty natural extension of the "for" syntax.
Why foreach at all? for (declaration-list; expression) body // like foreach before for(declaration-list ; expression ; expression) body // stays as is
| 2) The type declaration
| The type declaration in the foreach syntax is redundant, since it should
| match the type of elements in the collection. I think the compiler should be
| able to determine this somehow (this would require new syntax for collection
| classes, similar to templates). Rather similar to the new type safe
| collections in Java, which I like too.

Might be nice but if it is added here it would seem odd that foreach is
the only place declaration types get inferred. What about
void foo()
{
   x=1; // c'mon, D, you know what type I want ;-)
}
And someone else mentioned template instantiation. There's a can of worms
in them thar hills.
That's why I proposed let a while ago. void foo() { let x=1; } Well, it was intended to be used in some template-code, as you otherwise will result in code like typeof(a*b) c = a*b; which is pretty redundant. But I like it in a VERY common case: let x = new SomeClassName(); instead of SomeClassName x = new SomeClassName();
Mar 05 2004
next sibling parent J Anderson <REMOVEanderson badmama.com.au> writes:
Matthias Becker wrote:

Why foreach at all?

for (declaration-list; expression) body // like foreach before
for(declaration-list ; expression ; expression) body // stays as is
  
Having foreach instead of for, prevents syntax errors. -- -Anderson: http://badmama.com.au/~anderson/
Mar 05 2004
prev sibling parent reply "Jeroen van Bemmel" <someone somewhere.com> writes:
| Possible alternatives:
| foreach( uint v from aa ) { ... }
| foreach( uint v in aa ) { ... }
| foreach( uint v <- aa ) { ... }
| foreach( uint v : aa ) { ... }
|
| "from" and "in" would mean additional keywords, which I don't like too
much.
| My personal preference is the last one using ':'

The "foreach" syntax should parallel the "for" syntax:
 foreach(declaration-list ; expression) body
 for(declaration-list ; expression ; expression) body
The declaration-list is a comma separated list of looping variables.
Seems
like a pretty natural extension of the "for" syntax.
But that's just my point: they are not completely parallel. 'declaration-list' can only be 1 variable in foreach, and 'expression' denotes neither a termination conditional expression nor the expression calculated for the next loop. The syntax should be restricted to (as it is currently implemented): foreach( <type-name> <variable> ; <expression> ) So all of the following are wrong (these could be test cases...): foreach( int a,b; as ) { ... } // syntax error foreach( int a; 1 ) { ... } // semantic error: '1' is not a collection type Now that I think about it, how about allowing "foreach( int a : 1..10 ) { ... }" // a..b denotes the sequence of integers from a to b, inclusive, as used in splicing
 Why foreach at all?

 for (declaration-list; expression) body // like foreach before
 for(declaration-list ; expression ; expression) body // stays as is
I agree with J Anderson, it's not exactly the same so don't use the same syntax
| 2) The type declaration
| The type declaration in the foreach syntax is redundant, since it
should
| match the type of elements in the collection. I think the compiler
should be
| able to determine this somehow (this would require new syntax for
collection
| classes, similar to templates). Rather similar to the new type safe
| collections in Java, which I like too.

Might be nice but if it is added here it would seem odd that foreach is
the only place declaration types get inferred. What about
Yes, I know there's lots of other places where types might be inferred. But since 'foreach' already pretends to be a syntactic simplification of a common construct, if anywhere it should be applied there
void foo()
{
   x=1; // c'mon, D, you know what type I want ;-)
}
And someone else mentioned template instantiation. There's a can of worms
in them thar hills.
That's why I proposed let a while ago. void foo() { let x=1; } Well, it was intended to be used in some template-code, as you otherwise
will
 result in code like

 typeof(a*b) c = a*b;

 which is pretty redundant. But I like it in a VERY common case:

 let x = new SomeClassName();

 instead of

 SomeClassName x = new SomeClassName();
Mar 08 2004
parent "Jeroen van Bemmel" <someone somewhere.com> writes:
 But that's just my point: they are not completely parallel.
 'declaration-list' can only be 1 variable in foreach, and 'expression'
 denotes neither a termination conditional expression nor the expression
 calculated for the next loop. The syntax should be restricted to (as it is
 currently implemented):

 foreach( <type-name> <variable> ; <expression> )

 So all of the following are wrong (these could be test cases...):

 foreach( int a,b; as ) { ... }     // syntax error
 foreach( int a; 1 ) { ... }         // semantic error: '1' is not a
 collection type
Sorry, this was before I actually read the manual... It seems that for specific collections (the ones supporting indices) you can use at most 2 variables, 1 receiving the index and the other the value / reference of the items in the collection. At first sight this feature hurts my eyes while reading about it. Too many exceptional cases for my taste As long as we're doing things implicitly, why not have something like this: foreach<c> : "a_string" { printf( "%d: '%c'"), c.index. c ); } where 'c.index' is defined for collections supporting indices (and could be computed for the ones that don't) After all, 'foreach' could be considered a template where all that's missing is the name of the iteration variable...
Mar 08 2004
prev sibling parent "C. Sauls" <ibisbasenji yahoo.com> writes:
 void foo()
 {
    x=1; // c'mon, D, you know what type I want ;-)
 }
*response from D* "No I don't... I mean sure, you want an integral, but a s a byte, ubyte, short, ushort, int, uint, long, ulong, cent, ucent, or what?" Hmm.. no, I think I'd just assume have to tell it. Its not like it takes long to type 'int'. As for the type being given for the foreach parameter, what if I have multiple types I can iterate with? -C. Sauls -Invironz
Mar 07 2004