digitalmars.D - Maybe we don't need foreach ;-)
- Bill Baxter (20/20) Oct 30 2006 Just like some people have said, you can do everything with 'for'.
- Walter Bright (5/29) Oct 30 2006 'in' is already an operator, so that wouldn't work.
- Bill Baxter (21/53) Oct 30 2006 For one used to C for loops, yes. But Python for loops look like
- Burton Radons (28/64) Nov 01 2006 Who is more likely to move to D - a C/C++ programmer who also knows
- Reiner Pope (11/11) Oct 30 2006 I don't see much reason to change the syntax here, since:
- Bill Baxter (16/28) Oct 30 2006 It's more about saving a keyword in the grammar than saving typing.
- Walter Bright (5/7) Oct 30 2006 for (a, b; c)
- Bill Baxter (12/21) Oct 30 2006 Assuming you mean literally a b and c, it's pretty clear it's got to be
- Walter Bright (2/17) Oct 30 2006
- Bill Baxter (5/11) Oct 30 2006 I see. I didn't realize this property stuff extended to plain functions...
- Bruno Medeiros (8/14) Oct 31 2006 No it doesn't. It provides no semantic generalization/orthogonality *as
- Lionello Lunesu (20/20) Oct 30 2006 I got so used to foreach in D, I've just ported it to C ;)
- Frits van Bommel (13/27) Oct 31 2006 I think you have a dangling-else bug here:
- Lionello Lunesu (4/35) Oct 31 2006 Good one, easily solvable though, by inverting __B and using "if () {}
- Walter Bright (3/4) Oct 31 2006 I believe Eric Niebler wrote one too for C++ using preprocessor
Just like some people have said, you can do everything with 'for'. Well, actually maybe you can. It occurred to me that foreach and for really don't clash. One requires two semicolons, the other only one. So instead of a foreach we could have had for(a; aggregate) { } or if the keyword 'in' had been used for the new construct instead of borrowing from c's ; syntax it would be: for(a in aggregate) { ... } which could quite peacefully coexist with good-ole for (int i=0; i<10; i++) { } Oh well. Too much momentum behind foreach and foreach_reverse now, I suppose, to make such a simplification. --bb
Oct 30 2006
Bill Baxter wrote:Just like some people have said, you can do everything with 'for'. Well, actually maybe you can. It occurred to me that foreach and for really don't clash. One requires two semicolons, the other only one. So instead of a foreach we could have had for(a; aggregate) { }That looks like a syntax error for one used to for loops.or if the keyword 'in' had been used for the new construct instead of borrowing from c's ; syntax it would be: for(a in aggregate) { ... }'in' is already an operator, so that wouldn't work.which could quite peacefully coexist with good-ole for (int i=0; i<10; i++) { } Oh well. Too much momentum behind foreach and foreach_reverse now, I suppose, to make such a simplification.foreach is a fairly well understood term, I think it needs less explanation than a variant on for.
Oct 30 2006
Walter Bright wrote:Bill Baxter wrote:For one used to C for loops, yes. But Python for loops look like for a in aggregate: ... Bash for loops look like for f in list; do ... done There is certainly precedent for using 'for' synonymously with 'for each'.Just like some people have said, you can do everything with 'for'. Well, actually maybe you can. It occurred to me that foreach and for really don't clash. One requires two semicolons, the other only one. So instead of a foreach we could have had for(a; aggregate) { }That looks like a syntax error for one used to for loops.It already has multiple duties as a storage type, so that alone shouldn't be an issue. But I suppose you're right that it won't work here since a standard for loop can start with an Expression, which can contain an 'in'. So this would require arbitrary lookahead to see if there are any ';''s coming or not. Anyway, it wouldn't be a problem in a foreach :-). foreach can only start with ForeachTypeList so there would be no problems with: foreach(a in aggregate) { } as far as I can tell.or if the keyword 'in' had been used for the new construct instead of borrowing from c's ; syntax it would be: for(a in aggregate) { ... }'in' is already an operator, so that wouldn't work.Perhaps. But we're talking about epsilon vs 2*epsilon in terms of the amount of explanation required. One thing foreach has going for it is that it makes it feasible to replace the ';' with the 'in' keyword. :-) --bbwhich could quite peacefully coexist with good-ole for (int i=0; i<10; i++) { } Oh well. Too much momentum behind foreach and foreach_reverse now, I suppose, to make such a simplification.foreach is a fairly well understood term, I think it needs less explanation than a variant on for.
Oct 30 2006
Bill Baxter wrote:Walter Bright wrote:Who is more likely to move to D - a C/C++ programmer who also knows Python/Bash, or a dedicated Python or Bash programmer?Bill Baxter wrote:For one used to C for loops, yes. But Python for loops look like for a in aggregate: ... Bash for loops look like for f in list; do ... done There is certainly precedent for using 'for' synonymously with 'for each'.Just like some people have said, you can do everything with 'for'. Well, actually maybe you can. It occurred to me that foreach and for really don't clash. One requires two semicolons, the other only one. So instead of a foreach we could have had for(a; aggregate) { }That looks like a syntax error for one used to for loops.Arbitrary lookahead is no problem for D (it has to do this anyway, a lot, and this is a good thing as it's more important for a language to be comprehensible to the user, and minimise redundant information, than it is for it to be simple to parse), and is makes logical sense, as it iterates over all "a" which are in "aggregate". For example: where (uint a; a < 100) // Iterate from 0 to 99. where (a; a >= 0 && a < 100 && a % 2) // Iterate over every odd value from 0 to 99. where (a; a in list1 && a in list2) // Set intersection. where (a; a in list1 || a in list2) // Set union. where (a; a in list1 && a !in list2) // Set difference. auto list3 = where (a; a in list1 && a in list2); // Wee! This is pretty easy to do terribly, somewhat harder to do usefully, very hard to do intelligently, and incomprehensibly hard to do at peak optimisability in all cases. I'm not proposing it as a D feature, it's very much not in its style and it's something you'd spend twenty years progressively optimising, but it would be fun to have these kinds of advanced data-processing features in a fast language. So long as we're in fantasy-land: where (a; 0 <= a < 100) Ah, that's better. C's idea that logical operations belong on the same continuum as equations is so very, very 60s. And if we're no longer working with such outdated logic: where (a; a in (list1 && list2)); Makes sense to me.It already has multiple duties as a storage type, so that alone shouldn't be an issue. But I suppose you're right that it won't work here since a standard for loop can start with an Expression, which can contain an 'in'. So this would require arbitrary lookahead to see if there are any ';''s coming or not.or if the keyword 'in' had been used for the new construct instead of borrowing from c's ; syntax it would be: for(a in aggregate) { ... }'in' is already an operator, so that wouldn't work.
Nov 01 2006
I don't see much reason to change the syntax here, since: - it provides no generalizations/abstractions - it only saves 4 keys of typing - it isn't easier to read; perhaps even *harder* (you don't know whether it is a custom iterator or a 'normal' for loop) - Walter's right: it could increase bugs, such as: for (char[] key, char[] value; aggregate) which looks similar to for (char[] key; char[] value; aggregate) Cheers, Reiner
Oct 30 2006
Reiner Pope wrote:I don't see much reason to change the syntax here, since: - it provides no generalizations/abstractionsIt generalizes 'for'.- it only saves 4 keys of typingIt's more about saving a keyword in the grammar than saving typing.- it isn't easier to read; perhaps even *harder* (you don't know whether it is a custom iterator or a 'normal' for loop)Yeh, that's sort of true, but 90% of regular for loops have a ++ or -- or += or .next() in them at the end that make them pretty easy to recognize as regular for loops. Any for loop that doesn't fit that pattern already takes some scrutiny to figure out.- Walter's right: it could increase bugs, such as: for (char[] key, char[] value; aggregate) which looks similar to for (char[] key; char[] value; aggregate)That'd be a syntax error. You cannot declare variables in the second clause of a standard for-loop. You can only have an Expression there. But yeh, I'm sure you can cook up some example where you change one comma to a semicolon and both are legal. Anyway, the real answer is trailing delegates. This wasn't a serious proposal for change, more just musing on what could have been. foreach didn't really have to be a keyword, I don't think, that's the only observation I was trying to make. --bb
Oct 30 2006
Bill Baxter wrote:But yeh, I'm sure you can cook up some example where you change one comma to a semicolon and both are legal.for (a, b; c) for (a; b; c) Not only do they look very, very similar, it is not at all obvious which one was intended.
Oct 30 2006
Walter Bright wrote:Bill Baxter wrote:Assuming you mean literally a b and c, it's pretty clear it's got to be a foreach that was intended. There's no reason to stick a variable in either the first or last clause of a standard for. Here's a example where the intent really isn't obvious: for (int a; b;) for (int a; b) Anyway, given that * I myself have been guilty of using ',' where I meant ';' in for loops, * 'in' can't be used in place of ';' due to syntactical ambiguities, I agree that it's safer and better to have foreach separate. --bbBut yeh, I'm sure you can cook up some example where you change one comma to a semicolon and both are legal.for (a, b; c) for (a; b; c) Not only do they look very, very similar, it is not at all obvious which one was intended.
Oct 30 2006
Bill Baxter wrote:Assuming you mean literally a b and c, it's pretty clear it's got to be a foreach that was intended. There's no reason to stick a variable in either the first or last clause of a standard for.There is if a and b are function names.Here's a example where the intent really isn't obvious: for (int a; b;) for (int a; b) Anyway, given that * I myself have been guilty of using ',' where I meant ';' in for loops, * 'in' can't be used in place of ';' due to syntactical ambiguities, I agree that it's safer and better to have foreach separate. --bb
Oct 30 2006
Walter Bright wrote:Bill Baxter wrote:I see. I didn't realize this property stuff extended to plain functions too. I would be strongly inclined to wedgie anyone who made extensive use of that feature. :-) --bbAssuming you mean literally a b and c, it's pretty clear it's got to be a foreach that was intended. There's no reason to stick a variable in either the first or last clause of a standard for.There is if a and b are function names.
Oct 30 2006
Bill Baxter wrote:Reiner Pope wrote:No it doesn't. It provides no semantic generalization/orthogonality *as well as* no syntactic generalization/orthogonality either. If you think of the D grammar, the 'foreach' rule is removed, but another, similar one is added to the 'for' rule alternatives. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DI don't see much reason to change the syntax here, since: - it provides no generalizations/abstractionsIt generalizes 'for'.
Oct 31 2006
I got so used to foreach in D, I've just ported it to C ;) namespace D { template <typename T, int S> inline size_t length( T (&a)[S] ) { return S; } // Add overloads for your own containers } #define foreach(ELEMENT,ARRAY) \ for(size_t __L=D::length(ARRAY),__B=0,__I=0; !__B && __I<__L; assert(__L==D::length(ARRAY)), ++__I ) \ if (__B = 1) \ for(ELEMENT = ARRAY[__I]; __B; __B=0) // a break must make the main loop stop Don't get too scared; Microsoft's compiler does a great job optimizing that loop. In fact, if you don't use 'break', the second loop will disappear completely. I haven't checked the generated code on other compilers yet. You use it like this (yes, it's C): int nums[] = {1,2,3,4}; foreach(int i,nums) { } foreach(int &i,nums) { i=2; } L.
Oct 30 2006
Lionello Lunesu wrote:I got so used to foreach in D, I've just ported it to C ;) namespace D { template <typename T, int S> inline size_t length( T (&a)[S] ) { return S; } // Add overloads for your own containers } #define foreach(ELEMENT,ARRAY) \ for(size_t __L=D::length(ARRAY),__B=0,__I=0; !__B && __I<__L; assert(__L==D::length(ARRAY)), ++__I ) \ if (__B = 1) \ for(ELEMENT = ARRAY[__I]; __B; __B=0) // a break must make the main loop stopI think you have a dangling-else bug here: if (whatever) foreach(elt, arr) { something(); } else somethingelse(); What happens in this code? It looks like somethingelse() will be executed if whatever evaluates to false, but IIRC the 'else' clause will bind to the 'if' you have in your macro. Since that one never evaluates to false, somethingelse() will never be called here. I haven't tried it though, this was just from looking at it. Also, this won't manifest itself if you always use braces after 'if's so this may be hard to spot the one time you forget :).
Oct 31 2006
Frits van Bommel wrote:Lionello Lunesu wrote:Good one, easily solvable though, by inverting __B and using "if () {} else for...".. Thanks! L.I got so used to foreach in D, I've just ported it to C ;) namespace D { template <typename T, int S> inline size_t length( T (&a)[S] ) { return S; } // Add overloads for your own containers } #define foreach(ELEMENT,ARRAY) \ for(size_t __L=D::length(ARRAY),__B=0,__I=0; !__B && __I<__L; assert(__L==D::length(ARRAY)), ++__I ) \ if (__B = 1) \ for(ELEMENT = ARRAY[__I]; __B; __B=0) // a break must make the main loop stopI think you have a dangling-else bug here: if (whatever) foreach(elt, arr) { something(); } else somethingelse(); What happens in this code? It looks like somethingelse() will be executed if whatever evaluates to false, but IIRC the 'else' clause will bind to the 'if' you have in your macro. Since that one never evaluates to false, somethingelse() will never be called here. I haven't tried it though, this was just from looking at it. Also, this won't manifest itself if you always use braces after 'if's so this may be hard to spot the one time you forget :).
Oct 31 2006
Lionello Lunesu wrote:I got so used to foreach in D, I've just ported it to C ;)I believe Eric Niebler wrote one too for C++ using preprocessor wizardry. I've never been able to figure out how it worked <g>.
Oct 31 2006