www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - foreach syntax

reply "Namespace" <rswhite4 googlemail.com> writes:
A friend of mine ask me why D's foreach isn't like C#

Means, why is it like
int[] arr = [1, 2, 3];

foreach (int val; arr) {

and not
foreach (int val in arr) {

which it is more intuitive.

I could give him no clever answer to, so maybe someone here knows 
the reasons.
Jun 29 2012
next sibling parent Matthias Walter <xammy xammy.homelinux.net> writes:
On 06/29/2012 12:47 PM, Namespace wrote:
 A friend of mine ask me why D's foreach isn't like C#
 
 Means, why is it like
 int[] arr = [1, 2, 3];
 
 foreach (int val; arr) {
 
 and not
 foreach (int val in arr) {
 
 which it is more intuitive.
 
 I could give him no clever answer to, so maybe someone here knows the
 reasons.
 

I suppose it is because the usual 'for' loop is a relative of 'foreach'. And there we (and the C world) uses ';'.
Jun 29 2012
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Namespace:
 A friend of mine ask me why D's foreach isn't like C#

In D you often omit the type: foreach (val; arr) { Using "in" is better for the human programmers. But D is largely designed to make D compilers too happy. I think Walter said that the semicolon was preferred because it simplifies the compiler/compilation a little. Bye, bearophile
Jun 29 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 01:01 PM, bearophile wrote:
 Namespace:
 A friend of mine ask me why D's foreach isn't like C#

In D you often omit the type: foreach (val; arr) { Using "in" is better for the human programmers.

Certainly not. (except if 'human' means 'python' or 'C#'.) It is just as good as ';'.
 But D is largely
 designed to make D compilers too happy. I think Walter said that the
 semicolon was preferred because it simplifies the compiler/compilation a
 little.

It does not. Parsing the statements just about the same. In fact, only 2 lines in the DMD parser implementation need to be changed (slightly!) to implement the 'in' syntax instead.
Jun 29 2012
prev sibling next sibling parent Dejan Lekic <dejan.lekic gmail.com> writes:
On Fri, 29 Jun 2012 12:47:28 +0200, Namespace wrote:

 A friend of mine ask me why D's foreach isn't like C#
 
 Means, why is it like int[] arr = [1, 2, 3];
 
 foreach (int val; arr) {
 
 and not foreach (int val in arr) {
 
 which it is more intuitive.
 
 I could give him no clever answer to, so maybe someone here knows the
 reasons.

Because 1) "in" is a D keyword 2) D has even shorter syntax: foreach(val; arr) {} -- Dejan Lekic mailto:dejan.lekic(a)gmail.com http://dejan.lekic.org
Jun 29 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 12:47 PM, Namespace wrote:
 A friend of mine ask me why D's foreach isn't like C#

 Means, why is it like
 int[] arr = [1, 2, 3];

 foreach (int val; arr) {

foreach(val; arr) {
 and not
 foreach (int val in arr) {

 which it is more intuitive.

To someone coming from C#, yes.
 I could give him no clever answer to, so maybe someone here knows the
 reasons.

Just because. This does not matter.
Jun 29 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 04:16 PM, bearophile wrote:
 Timon Gehr:

 Just because. This does not matter.

Now and then I write foreach(x;y;data)

error: found ';' when expecting ')'
 or foreach(x,y,data) or

error: found ')' when expecting ';'
 foreach(x;y,data).

error: undefined identifier y
 "in" avoids some of those little mistakes.

foreach(x in y,data)
Jun 29 2012
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 04:23 PM, Timon Gehr wrote:
 ...
 foreach(x;y,data).

error: undefined identifier y

BTW, it would certainly be better if this didn't actually pass the parser.
Jun 29 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 04:34 PM, bearophile wrote:
 Timon Gehr:

 foreach(x in y,data)

There is no way to avoid all possible mistakes, but it's easier to mistake a ";" for a ",", than mistake a "in" for a ",".

I don't think optimizing the grammar for error cases that are not even compilable code is worthwhile at all.
 "in" is used for this purpose in Python, C#, and probably other
 languages because it's more readable

Probably it is used in those languages because it resembles mathematical notation, or let var in exp. I doubt there is anything deep behind it.
 than an arbitrary symbol like ";".

Probably, but when I read code, I don't read the ';', it is just a separator and helps orientation. Making separators 'readable' is imho a non-goal. But YMMV. Patching the parser so that it accepts both forms takes 20 seconds.
Jun 29 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Timon Gehr:

 Just because. This does not matter.

Now and then I write foreach(x;y;data) or foreach(x,y,data) or foreach(x;y,data). "in" avoids some of those little mistakes. Bye, bearophile
Jun 29 2012
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Timon Gehr:

 foreach(x in y,data)

There is no way to avoid all possible mistakes, but it's easier to mistake a ";" for a ",", than mistake a "in" for a ",". "in" is used for this purpose in Python, C#, and probably other languages because it's more readable than an arbitrary symbol like ";". Bye, bearophile
Jun 29 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, June 29, 2012 16:34:33 bearophile wrote:
 Timon Gehr:
 foreach(x in y,data)

There is no way to avoid all possible mistakes, but it's easier to mistake a ";" for a ",", than mistake a "in" for a ",". "in" is used for this purpose in Python, C#, and probably other languages because it's more readable than an arbitrary symbol like ";".

And in Java, they use : rather than ; or in. This is completely subjective. I see _zero_ benefit in using in over ;. ; is nicely consistent with for, and is probably why foreach in D uses it. But regardless, it's purely a subjective choice. Walter picked what he picked. C# and python picked what they picked. Java picked what they picked. I really don't think that you can objectively argue that one is better than the other - not unless one is objectively easier to write the grammar for. Anything involving whether a person thinks in is or ; is easier to read or will cause fewer mistakes or whatnot is going to be purely subjective. - Jonathan M Davis
Jun 29 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, June 29, 2012 12:47:28 Namespace wrote:
 A friend of mine ask me why D's foreach isn't like C#
 
 Means, why is it like
 int[] arr = [1, 2, 3];
 
 foreach (int val; arr) {
 
 and not
 foreach (int val in arr) {
 
 which it is more intuitive.
 
 I could give him no clever answer to, so maybe someone here knows
 the reasons.

Probably because for uses ; rather than in. But it's a purely subjective language design decision. Walter could have used : like Java does, and it would have worked just as well. He decided to go with ;. On the whole, we was basing D on C++, not C#, so he didn't copy what C# was doing syntactically for anything AFAIK. Lots of stuff like this is going to vary from language to language, and often the decisions are arbitrary and have nothing to do with what other languages did or are based completely on the lanugage designer's personal preferences. If there's no technical reason for going with one over the other (and I'm not aware of one in this case), then it's up to the language designer to make a choice on it which is going to be completely subjective. - Jonathan M Davis
Jun 29 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 06:09 PM, Namespace wrote:
 It wasn't my intention to start a syntax war. :D
 But i must agree, that "in" is a lot more readable as ";". Event ":" ist
 more readable as ";". But i just would know the real reason to this
 decision. Tanks to all. :)
 But why correct a few guys here my code?

It was more of a suggestion than a correction.
 foreach (int val; is the same as foreach(val; except that i like to
 write which type "val" is. Is that against the D nature or what?

It is redundant.
 P.S.: Which line must be changed to allow the "in2 syntax?
 Just out of pure interest. Thanks.

Search for TOKforeach in parse.c and change the TOKsemicolon's around there to TOKin's. If you want to allow both, that should be straightforward as well.
Jun 29 2012
next sibling parent David <d dav1d.de> writes:
Am 29.06.2012 18:23, schrieb Namespace:
 You mean line 3817 change to
 if (t->value == TOKcomma || t->value == TOKsemicolon || t->value ==
 TOKin) ?
 But i have to rebuild dmd or not? I'm a windows user and I never build
 dmd on my own.

Jun 29 2012
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 06:27 PM, Namespace wrote:
 You mean just change line 3817 to
 if (t->value == TOKcomma || t->value == TOKsemicolon || t->value ==
 TOKin) ?
 But know i have to rebuild dmd (i use windows), and i never did this
 before. :/

You'll also have to change the line that says expect(TOKsemicolon);
Jun 29 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 07:50 PM, Namespace wrote:
 You'll also have to change the line that says expect(TOKsemicolon);

In what? comment out?

Looking at some other parts of the parse.c source reveals that if(token.value == TOKin) nextToken(); else expect(TOKsemicolon); might get you going.
Jun 29 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 08:04 PM, Namespace wrote:
 On Friday, 29 June 2012 at 17:55:57 UTC, Timon Gehr wrote:
 On 06/29/2012 07:50 PM, Namespace wrote:
 You'll also have to change the line that says expect(TOKsemicolon);

In what? comment out?

Looking at some other parts of the parse.c source reveals that if(token.value == TOKin) nextToken(); else expect(TOKsemicolon); might get you going.

I think i'm to stupid for that, sry.

My bad: Replacing the line with the following, together with the other change you made, works: if(token.value == TOKin) nextToken(); else check(TOKsemicolon);
Jun 29 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 08:18 PM, Namespace wrote:
 My bad:

 Replacing the line with the following, together with the other change
 you made, works:

 if(token.value == TOKin) nextToken(); else check(TOKsemicolon);

Impressive, thanks a lot, sometimes I'm a bit stupid. :) Last question: It works fine, but i'm getting now "DMD v2.059 DEBUG" if i compile. Do I need a special flag by recompiling?

I don't have a windows system handy, but you could try the following: make -fwin32.mak release
Jun 29 2012
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 07:47 PM, Namespace wrote:
 On Friday, 29 June 2012 at 17:08:36 UTC, Namespace wrote:
 Which is easy.

Even on Windows? :O

I tried with win32.mak in src/dmd and i get a dmd.exe. But the compiler still says "found 'in' when expecting ';'!" if i try to write foreach (val in vals) {. Have i edit the wrong line in paste.c or fails my build?

You have to edit both relevant lines.
Jun 29 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 09:51 PM, Namespace wrote:
 But there is no overhead or something else _if_ i put the type, or?

There is a slight typing and compilation overhead. Nothing significant.
Jun 29 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/29/2012 10:02 PM, Roman D. Boiko wrote:
 On Friday, 29 June 2012 at 19:52:33 UTC, Timon Gehr wrote:
 On 06/29/2012 09:51 PM, Namespace wrote:
 But there is no overhead or something else _if_ i put the type, or?

There is a slight typing and compilation overhead. Nothing significant.

You missed a slight reading overhead.

Good catch.
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
It wasn't my intention to start a syntax war. :D
But i must agree, that "in" is a lot more readable as ";". Event 
":" ist more readable as ";". But i just would know the real 
reason to this decision. Tanks to all. :)
But why correct a few guys here my code?
foreach (int val; is the same as foreach(val; except that i like 
to write which type "val" is. Is that against the D nature or 
what?

P.S.: Which line must be changed to allow the "in2 syntax?
Just out of pure interest. Thanks.
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 It is redundant.

But informative.
 Search for TOKforeach in parse.c and change the TOKsemicolon's 
 around there to TOKin's. If you want to allow both, that should 
 be
 straightforward as well.

I will try.
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
You mean line 3817 change to
if (t->value == TOKcomma || t->value == TOKsemicolon || t->value 
== TOKin) ?
But i have to rebuild dmd or not? I'm a windows user and I never 
build dmd on my own.
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
You mean just change line 3817 to
if (t->value == TOKcomma || t->value == TOKsemicolon || t->value 
== TOKin) ?
But know i have to rebuild dmd (i use windows), and i never did 
this before. :/
Jun 29 2012
prev sibling next sibling parent "Tobias Pankrath" <tobias pankrath.net> writes:
On Friday, 29 June 2012 at 16:27:23 UTC, Namespace wrote:
 You mean just change line 3817 to
 if (t->value == TOKcomma || t->value == TOKsemicolon || 
 t->value == TOKin) ?
 But know i have to rebuild dmd (i use windows), and i never did 
 this before. :/

Which is easy. I write a guide as soon as time permits.
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 Which is easy.

Even on Windows? :O
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Friday, 29 June 2012 at 17:08:36 UTC, Namespace wrote:
 Which is easy.

Even on Windows? :O

I tried with win32.mak in src/dmd and i get a dmd.exe. But the compiler still says "found 'in' when expecting ';'!" if i try to write foreach (val in vals) {. Have i edit the wrong line in paste.c or fails my build?
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 You'll also have to change the line that says 
 expect(TOKsemicolon);

In what? comment out?
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Friday, 29 June 2012 at 17:55:57 UTC, Timon Gehr wrote:
 On 06/29/2012 07:50 PM, Namespace wrote:
 You'll also have to change the line that says 
 expect(TOKsemicolon);

In what? comment out?

Looking at some other parts of the parse.c source reveals that if(token.value == TOKin) nextToken(); else expect(TOKsemicolon); might get you going.

I think i'm to stupid for that, sry. I comment out "check" (just for testing) but then i get much more errors if i try to compile "foreach (val in vals) {".
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 My bad:

 Replacing the line with the following, together with the other 
 change you made, works:

 if(token.value == TOKin) nextToken(); else check(TOKsemicolon);

Impressive, thanks a lot, sometimes I'm a bit stupid. :) Last question: It works fine, but i'm getting now "DMD v2.059 DEBUG" if i compile. Do I need a special flag by recompiling?
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 make -fwin32.mak release

That simple... :) Many thanks!
Jun 29 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, June 29, 2012 18:16:23 Namespace wrote:
 It is redundant.

But informative.

It's very common in D to not put the type unless it's absolutely necessary (e.g. use auto everywhere). This can be both good and bad for code readability and maintenance, but it's particularly useful with generic code, which is generally promoted quite heavily. So, I think that you'll find that most of the people around here generally don't explicitly use the type unless they need to (though there's always someone who's an exception). - Jonathan M Davis
Jun 29 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
But there is no overhead or something else _if_ i put the type, 
or?
Jun 29 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, June 29, 2012 21:51:20 Namespace wrote:
 But there is no overhead or something else _if_ i put the type,
 or?

No. It's like auto. The type is inferred. It's all statically typed and strongly typed. It's not like it figures out the type at runtime or anything like that. It's all done at compile time. It's just like C++11's auto. It makes refactoring code a lot easier, and it makes generic code a _lot_ easier to write. Without auto, std.algorithm would pretty much be impossible (you _could_ do it, but it would be so disgusting that no one would want to use it, because all of those compound range types get truly hideous if you actually look at the types themselves - voldemort types have reduced that problem, but they'd be impossible without auto anyway). It's up to you whether you want to put types explicitly or use let them be inferred with auto or in foreach loops, but it's more or less common practice at this point to use type inferrence very heavily and to avoid using types explicitly except when you need to. - Jonathan M Davis
Jun 29 2012
prev sibling parent "Roman D. Boiko" <rb d-coding.com> writes:
On Friday, 29 June 2012 at 19:52:33 UTC, Timon Gehr wrote:
 On 06/29/2012 09:51 PM, Namespace wrote:
 But there is no overhead or something else _if_ i put the 
 type, or?

There is a slight typing and compilation overhead. Nothing significant.

You missed a slight reading overhead.
Jun 29 2012