foreach enhancement

C

cody

What about an enhancement of foreach loops which allows a syntax like that:

foeach(int i in 1..10) { } // forward
foeach(int i in 99..2) { } // backwards
foeach(char c in 'a'..'z') { } // chars
foeach(Color c in Red..Blue) { } // using enums

It should work with all integral datatypes. Maybe we can step a bit further:

foeach(int i in 1..10, 30..100) { } // from 1 to 10 and 30 to hundred

And maybe we could also try to enhance the loop further and make it usable
for floating point types too:

foeach(float f in 1.0..9.5 : 0.5) { } // from 1.0 to 9.5 in steps of 0.5

This is far more readable as a for loop and makes the intend much clearer.
I always have to think if I write loops like "for (int i=list.Count-1; i<=0;
i--)".
This is unproductive and errorprone and hard to maintain. Thus, my proposal.
 
W

William Stacey [MVP]

I'll vote for it. Could probably work in regex match sets into that as well
or any kind of "set" work.
 
D

Daniel O'Connell [C# MVP]

William Stacey said:
I'll vote for it. Could probably work in regex match sets into that as
well
or any kind of "set" work.
Or you could just use iterators to generate functions that achieve what you
want without adding to the language.

foreach (int i in From(1,10))

or
foreach (char c in From('a','z'))

or
foreach (string s in RegexMatch(string,regexPattern))

etc.

adding several syntax additions(..., :, and , in this case) to the langauge
for this edge case is a touch to far, I think.

Now, if you can extend the concept out to inline array expressions or other
expressions in general you could get yourself in a much stronger position.

Consider something like(these are all psuedo syntax, just suggestions)

int[] x = [1...10 : 2]; // equivilent to new int[] { 1,3,5,7,9 }

or perhaps
int[] x = [1 : 2 -> 10]; //equilvilent to new int[]
{1,3,5,7,9,11,13,15,17,19}

or other bits of set\array syntax.

Still, fitting it into the langauge will take some doing, I havn't even
started to consider language contradictions this syntax may cause.
--
William Stacey, MVP

cody said:
What about an enhancement of foreach loops which allows a syntax like that:

foeach(int i in 1..10) { } // forward
foeach(int i in 99..2) { } // backwards
foeach(char c in 'a'..'z') { } // chars
foeach(Color c in Red..Blue) { } // using enums

It should work with all integral datatypes. Maybe we can step a bit further:

foeach(int i in 1..10, 30..100) { } // from 1 to 10 and 30 to hundred

And maybe we could also try to enhance the loop further and make it
usable
for floating point types too:

foeach(float f in 1.0..9.5 : 0.5) { } // from 1.0 to 9.5 in steps of 0.5

This is far more readable as a for loop and makes the intend much
clearer.
I always have to think if I write loops like "for (int i=list.Count-1; i<=0;
i--)".
This is unproductive and errorprone and hard to maintain. Thus, my proposal.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
 
S

Shakir Hussain

I feel major enhancement required in foreach is allowing the collection
value to be changed during runtime. In some situations, Adding and deleting
a value from collection is required. Foreach statement does not support it
(for good reason may be)

My thoughts (or requests)

1. Allow the collection value to be changed

example -

foreach(XmlNode pNode in pNodeList)
{
//allow new node to be added
pNodeList.Add(newNode);

//allow pNode to be removed inside foreach.
}

2. Now the tricky part is refreshing collection and starting the foreach
loop again for modified collection.

foreach(XmlNode pNode in pNodeList)
{
if(MyConditionMet == true)
{
pNodeList.Add(newNode);
pNodeList.Refresh () //refreshing collection.

MyConditionMet = false;

//command to restart the foreach loop breaking current one
since collection is modified
foreach.ReStart_And_Break_current;
}
}

Comments are welcomed
 
C

cody

Or you could just use iterators to generate functions that achieve what
you
want without adding to the language.

foreach (int i in From(1,10))

or
foreach (char c in From('a','z'))

or
foreach (string s in RegexMatch(string,regexPattern))

etc.

adding several syntax additions(..., :, and , in this case) to the langauge
for this edge case is a touch to far, I think.

Maybe the last two examples I have in my post where really a touch too far,
but they are the logical next step if we would allow the simplest case
"foreach )int i in 0..10)".

Nobody would use your suggested generator methods because they are more
typing than it would be without them. Additionally Iam not sure wheather the
jitter is able to optimize this Gerenator methods so that they generate the
same code as if a normal for loop was used.

Loops are one of the most common things in programming so making them more
readable and safer is IMO a highly desireable goal.
Now, if you can extend the concept out to inline array expressions or other
expressions in general you could get yourself in a much stronger position.

Consider something like(these are all psuedo syntax, just suggestions)

int[] x = [1...10 : 2]; // equivilent to new int[] { 1,3,5,7,9 }

or perhaps
int[] x = [1 : 2 -> 10]; //equilvilent to new int[]
{1,3,5,7,9,11,13,15,17,19}

or other bits of set\array syntax.

Great idea but maybe this is already too much of the good..
Still, fitting it into the langauge will take some doing, I havn't even
started to consider language contradictions this syntax may cause.

It certainly would't fit into C/C++ but it will fit into C#. We already have
a foreach,
and if a foreach fits into the language then the simplification syntax for
loops from x to y will also fit.
 
D

Daniel O'Connell [C# MVP]

cody said:
Maybe the last two examples I have in my post where really a touch too
far,
but they are the logical next step if we would allow the simplest case
"foreach )int i in 0..10)".

Nobody would use your suggested generator methods because they are more
typing than it would be without them. Additionally Iam not sure wheather
the
jitter is able to optimize this Gerenator methods so that they generate
the
same code as if a normal for loop was used.

Loops are one of the most common things in programming so making them more
readable and safer is IMO a highly desireable goal.

As someone said not to long ago, you entirely missed the point. Loops are
common, but looping over a series of static numbers is so rare that it
deserves *no* extra syntax. 90%+ of loops are going to be between one static
number and a dynamic one or using an enumerator.

Using the generator methods is simply a *way* to do it that is realistic(and
more flexible than the syntax is going to do), adding all this type of
complexity for the purposes of simple loops is just a bad idea, like it or
not. Its like asking for a teleporter because you don't feel like walking to
the bathroom. Adding significant syntax extensions that are so limited in
use is pretty bad. While foreach has a limited use, it is the same syntax as
few others(using and lock come to mind) its just a new keyword with
specified behaviour(with in of course, but that is a matched pair of
keywords actually, foreach ... in). Adding this syntax adds entirely new
concepts to the langauge at the very very very bottom of the usage tree. If
it can't scale beyond foreach its a bad idea, or atleast an incomplete one.
In essence you are asking for list and\or array literals without realizing
it, however you are asking for it in very limited scope.

Have you ever designed a compiler? Or played with one? If you havn't I
highly recommend you do, it might help understand the issues with language
design. The mono C# compiler is a good start, its fairly clean and its in
C#.

As for optimizing the code, neither is going to work unless the c#
*compiler* handles it. the JIT isn't going to recognize any specific usage
of IEnumerator as a for loop. Your syntax would allow it, but as far as
arrays go, the C# compiler handles them both just fine with similar, if not
identical, speed.

Don't avoid foreach because of a simple belief that foreach is slower than
for, you'll get bitten.
 
C

cody

Loops are one of the most common things in programming so making them
more
As someone said not to long ago, you entirely missed the point. Loops are
common, but looping over a series of static numbers is so rare that it
deserves *no* extra syntax. 90%+ of loops are going to be between one static
number and a dynamic one or using an enumerator.

You don't get it, do you. The special case of skipping numbers and having
multiple ranges in one loop were just an additional idea and I also said
that this maybe would already go too far.
The idea was simply to simplyfy common things like "for (int i=list.Count-1;
i<=0; i--)" which isn't very readable compared with "foreach (int i in
10..0)". I don't know where this is "too much complexity" or why this is "so
limited in use".
In essence you are asking for list and\or array literals without realizing
it, however you are asking for it in very limited scope.

I wouldn't go so far. It should be very enough to allow "x..n" in forech
loops only.
Introducing real list and\or array literals as your said would indeed
introduce lots of unneccesary complexity to the language and that wasn't
what I proposed.

Maybe for a future enhancement one could think about allowing such things
like

if (a in [0..10, 30..100]) { }

or

switch (a)
{
case 0..100: DoIt(); break;
}

which were allowed in pascal, but again these are additional ideas and not
the thing I asked for.
Have you ever designed a compiler? Or played with one? If you havn't I
highly recommend you do, it might help understand the issues with language
design.

I know, I know. The hardest question in language design is not what to put
in but what to leave out.
As for optimizing the code, neither is going to work unless the c#
*compiler* handles it. the JIT isn't going to recognize any specific usage
of IEnumerator as a for loop.

IEnumerator.MoveNext() and IEnumerator.Current can be inlined so I do not
see a reason why the jitter will not be able to handle it.
Don't avoid foreach because of a simple belief that foreach is slower than
for, you'll get bitten.

I use foreach whenever possible except the cases which foreach can't handle:
backward looping or looping over a range of numbers in general without a
collection involved.
Thats where my proposal comes in :)
 
D

Daniel O'Connell [C# MVP]

cody said:
You don't get it, do you. The special case of skipping numbers and having
multiple ranges in one loop were just an additional idea and I also said
that this maybe would already go too far.
The idea was simply to simplyfy common things like "for (int
i=list.Count-1;
i<=0; i--)" which isn't very readable compared with "foreach (int i in
10..0)". I don't know where this is "too much complexity" or why this is
"so
limited in use".

I get it fine, I just don't think you do. How often do you *really* do
backwards enumerations? How often do you *really* need this? This idea isn't
worth it. I'm trying not to put it harshly but you won't let me. Its
needless, wasted complexity. It is nothing that can't be done with a minimum
of additional typing, it adds *nothing* to the vast majority of code, but it
adds considerable complexity to understanding code and the specification of
foreach *without* supporting IEnumerator, which is what foreach *does*. Its
a good idea at its base but your implementation completely misses the sweet
spot.
I wouldn't go so far. It should be very enough to allow "x..n" in forech
loops only.
Introducing real list and\or array literals as your said would indeed
introduce lots of unneccesary complexity to the language and that wasn't
what I proposed.

I think, personally, that list or array literals would add a great deal to
the language, while your proposal will add functionality that list\array
literals encompasses without adding any real value.

Why do you think list and\or array literals are unnessecery? They would
solve *your* problem plus a host of others.
Maybe for a future enhancement one could think about allowing such things
like

if (a in [0..10, 30..100]) { }

or

switch (a)
{
case 0..100: DoIt(); break;
}

which were allowed in pascal, but again these are additional ideas and not
the thing I asked for.

And, frankly, carefully written, none of these are needed. A Contains method
on arrays and array literlas or list literals completely remove any need for
either of these constructs(
if ([0...10,30...100].Contains(a))
covers it).
I know, I know. The hardest question in language design is not what to put
in but what to leave out.

Thats the a hard part, but not the problem you are having. You are taking
too much out and providing an...impotent solution.

Whats more important is understanding expressions and statements. In this
case you are proposing an expression that is valid in only one circumstance,
which is a very rare thing or a specialized foreach statement. Neither one
is what *I* would do when designing a compiler, the generic list\array
literal makes alot more sense, IMHO.

Personally I would say the hardest part is designing so that you can add on
later without breaking anything. Most of the compilers I've written are
one-off or domain specific langauges. I don't *have* to consider the future
because the language has very little possible future. Languages like C#
don't have that luxury
IEnumerator.MoveNext() and IEnumerator.Current can be inlined so I do not
see a reason why the jitter will not be able to handle it.


I use foreach whenever possible except the cases which foreach can't
handle:
backward looping or looping over a range of numbers in general without a
collection involved.
Thats where my proposal comes in :)

Yes, but thats what for is for. Really, there is alot of stuff that list
literals fits into, including things like C-Omega\regex cardinalities. It
would solve a number of problems, unlike your current suggestion.

I don't want to come down hard, I like these ideas, I just don't think
you're hitting on realistic features so much as "would be nice for what I'm
doing right now" features.
--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
 
C

cody

Why do you think list and\or array literals are unnessecery? They would
solve *your* problem plus a host of others.

No I don't find them unnessecery, I only think that they -as you already
pointed out - would really add huge new complexity to the language. Btw, I
wouldn't call them list and\or array literals, they are more set literals.
Maybe for a future enhancement one could think about allowing such things
like

if (a in [0..10, 30..100]) { }

or

switch (a)
{
case 0..100: DoIt(); break;
}

And, frankly, carefully written, none of these are needed. A Contains method
on arrays and array literlas or list literals completely remove any need for
either of these constructs(
if ([0...10,30...100].Contains(a)) covers it).
Indeed.
I know, I know. The hardest question in language design is not what to put
in but what to leave out.

Thats the a hard part, but not the problem you are having. You are taking
too much out and providing an...impotent solution.

You mean Iam not consequent enough: If I put this extended foreach in I also
have to put (for the sake of language consistency) set literals and all
their uses in.
Yes, but thats what for is for. Really, there is alot of stuff that list
literals fits into, including things like C-Omega\regex cardinalities. It
would solve a number of problems, unlike your current suggestion.

What is C-Omega? I found nothing about it.

However, in conclusion I have to agree that adding this foreach feature
without introducing set literals would maybe a inconsistency in the
language, an exception which is valid in one case only, although I still
consider it useful.

Otherwise, adding full support for this set literals and stuff would indeed
add a huge complexity into the language and I'm not sure if this feature
wold fit into C# or add really much value. I cannot remember when I last
time really needed a set. In almost all cases a simple if (a>=x && a<=y) or
Array.IndexOf() solved the problem, and for strings we can use RegEx.

Now I wish you much fun for the rest of the weekend :)

cu
 
D

Daniel O'Connell [C# MVP]

cody said:
No I don't find them unnessecery, I only think that they -as you already
pointed out - would really add huge new complexity to the language. Btw, I
wouldn't call them list and\or array literals, they are more set literals.

I don't consider them sets. ALthough every example we've used has been a
set, one could easily break the set rule that there are no
duplicates([0...100,50..75]), making them array or list literals(depending
on implementation, does it return an Array or a IList<T>, for example). A
set would be possible via these literals but not guarenteed by it.

Maybe for a future enhancement one could think about allowing such things
like

if (a in [0..10, 30..100]) { }

or

switch (a)
{
case 0..100: DoIt(); break;
}

And, frankly, carefully written, none of these are needed. A Contains method
on arrays and array literlas or list literals completely remove any need for
either of these constructs(
if ([0...10,30...100].Contains(a)) covers it).
Indeed.
I know, I know. The hardest question in language design is not what to put
in but what to leave out.

Thats the a hard part, but not the problem you are having. You are taking
too much out and providing an...impotent solution.

You mean Iam not consequent enough: If I put this extended foreach in I
also
have to put (for the sake of language consistency) set literals and all
their uses in.

I am saying that there is little point in adding this syntax *without*
extending it, considering the difference in the compiler would probably be
about 7 or 8 lines. Lets say the list literal is an expression that returns
an IList<T>, foreach would simply accept that expression as its IEnumerable
source and be done with it(specialization could be done, in theory, to
generate a for if possible). However, since that expression pretty much
stands alone you can just add it as a valid expression in the various places
it makes sense and the compiler will just *work* anywhere that IList is
valid. A well designed compiler usually doesn't need to know what type of
expression is lying underneath another expression, it just needs to know
what type will be on the stack when that expression is finished(note that
flaws in the compiler or emission architecture or optimization work will
probably never allow a real compiler to exist like that, however its
something I would strive towards).
What is C-Omega? I found nothing about it.
Its a research language based off C# that is the result of the merging of
two other research languages: Xen and Polyphonic C#.
http://research.microsoft.com/Comega/

I don't like every thing about them, but the cardinalities are interesting.
However, in conclusion I have to agree that adding this foreach feature
without introducing set literals would maybe a inconsistency in the
language, an exception which is valid in one case only, although I still
consider it useful.

Otherwise, adding full support for this set literals and stuff would
indeed
add a huge complexity into the language and I'm not sure if this feature
wold fit into C# or add really much value. I cannot remember when I last
time really needed a set. In almost all cases a simple if (a>=x && a<=y)
or
Array.IndexOf() solved the problem, and for strings we can use RegEx.
I've seen quite a few requests for better array literal syntax. I'm not sure
something this complicated is warrented, granted, but some form of array
literal makes sense.
 
M

Michael C

A more robust implementation of the switch...case statements wouldn't be
unwelcome. Allowing multiple constant-expressions in the case labels would
be a nice addition. Obviously you can stack case labels, like this:

switch (myVar)
{
case 0:
case 2:
case 3:
case 5:
doSomething();
break;
case 1:
case 4:
doSomethingElse();
break;
}

But it would make it a little easier on my poor old tired fingers if I could
write a short-hand statement like this:

switch (myVar)
{
case 0, 2, 3, 5:
doSomething();
break;
case 1, 4:
doSomethingElse();
break;
}

This is obviously a simplified example that could be done several other ways
which would be simpler than switch...case, such as using if statements,
etc., but when you have 10 different statements to perform based on dozens
of different constant values, you start praying for shortcuts to save wear
and tear on the old phalanges. That is, after all, the only logical reason
they kept the conditional operator (?:) when if...else and assignment
statements work just as well...

Adding ranges to the definition of case constant-expressions is just an
extension of the idea of making life a little easier for the programmer,
isn't it? Trying to use if...else statements utilizing the Contains method
nested to the high-heavens to replicate the behavior of a 'complex' switch
statement would make your code even more unreadable and difficult to
maintain IMHO.

Thanks,
Michael C.
 
P

Paul Varjak 1961

cody said:
What about an enhancement of foreach loops which allows a syntax like
that:

foeach(int i in 1..10) { } // forward
foeach(int i in 99..2) { } // backwards
foeach(char c in 'a'..'z') { } // chars
foeach(Color c in Red..Blue) { } // using enums

It should work with all integral datatypes. Maybe we can step a bit
further:

foeach(int i in 1..10, 30..100) { } // from 1 to 10 and 30 to hundred

And maybe we could also try to enhance the loop further and make it usable
for floating point types too:

foeach(float f in 1.0..9.5 : 0.5) { } // from 1.0 to 9.5 in steps of 0.5

This is far more readable as a for loop and makes the intend much clearer.
I always have to think if I write loops like "for (int i=list.Count-1;
i<=0; i--)".
This is unproductive and errorprone and hard to maintain. Thus, my
proposal.

Look up 'generics'

java has this already, c# will get in 2.0
 
C

cody

I don't consider them sets. ALthough every example we've used has been a
set, one could easily break the set rule that there are no
duplicates([0...100,50..75]), making them array or list literals(depending
on implementation, does it return an Array or a IList<T>, for example). A
set would be possible via these literals but not guarenteed by it.

I consider it a set since the expression in the brackets in a set resulting
from a union from the sets 0...100 and 50..75.
The compiler will optimize this to simply 0..100. I don't think that set
literals needs a IList interface.
IEnumerable and the operator "in" would be enough. I cannot think of more
functionality that is needed.
Every variable that supports the operators <,<=,>,>= can be used in this
sets.
I often have the case: if (DateTime.Today >= dateFrom && DateTime.Today <=
dateTo) it would be simpler if we could write:
if (DateTime.Today in[dateFrom ..dateTo]).
Its a research language based off C# that is the result of the merging of
two other research languages: Xen and Polyphonic C#.
http://research.microsoft.com/Comega/

I don't like every thing about them, but the cardinalities are
interesting.

Seems extremeley complicated and I don't think it will make its way into
regular C# someday.
Putting SQL, Datasets or XML directly into the language seems a very bad
idea to me.
The chords of polyfonic C# seem interesting and but I cannot say that I
understood it: Multiple methods with just one body this is a bit confusing.
I've seen quite a few requests for better array literal syntax. I'm not sure
something this complicated is warrented, granted, but some form of array
literal makes sense.

What do you mean with array literal? In the set, internally no real
set/collection is created, the set literals is just a set of parameterized
rules.
It wouldn't be good if foreach (int i in 0..1000000) creates a huge array
internally.
I cannot imagine what real array literals should be good for.
 
D

Daniel Billingsley

I took "Unlike the C++ switch statement, C# does not support an explicit
fall through from one case label to another." from the doc to mean you
couldn't do that. But it works ok?
 
C

cody

But it would make it a little easier on my poor old tired fingers if I
could
write a short-hand statement like this:

switch (myVar)
{
case 0, 2, 3, 5:
doSomething();
break;
case 1, 4:
doSomethingElse();
break;
}


in that case you can just do:

if ((IList)new int[]{0,2,3,5}).Contains(myVar))
doSomething();
else if ((IList)new int[]{1,4}).Contains(1, 4))
doSomethingElse();

OK looks still very messy, maybe we really need set literals here..
 
J

Jon Skeet [C# MVP]

Daniel Billingsley said:
I took "Unlike the C++ switch statement, C# does not support an explicit
fall through from one case label to another." from the doc to mean you
couldn't do that. But it works ok?

It's fine - so long as you don't have code in between. You can do:

case 0:
case 1:
Foo();
break;

but you can't do:

case 0:
Foo();
case 1:
Bar();
break;
 
J

Jon Skeet [C# MVP]

cody said:
I don't consider them sets. ALthough every example we've used has been a
set, one could easily break the set rule that there are no
duplicates([0...100,50..75]), making them array or list literals(depending
on implementation, does it return an Array or a IList<T>, for example). A
set would be possible via these literals but not guarenteed by it.

I consider it a set since the expression in the brackets in a set resulting
from a union from the sets 0...100 and 50..75.

That seems less useful then. In particular, it means that it has no
order (as sets don't; sequences do). Do you really want 0...100 and
100...0 to be equivalent?
 
C

cody

I don't consider them sets. ALthough every example we've used has been
a
set, one could easily break the set rule that there are no
duplicates([0...100,50..75]), making them array or list literals(depending
on implementation, does it return an Array or a IList<T>, for example). A
set would be possible via these literals but not guarenteed by it.

I consider it a set since the expression in the brackets in a set resulting
from a union from the sets 0...100 and 50..75.

That seems less useful then. In particular, it means that it has no
order (as sets don't; sequences do). Do you really want 0...100 and
100...0 to be equivalent?


OK, OK it is more than a set. So the order matters and duplicates should be
allowed, but depending on the context the compiler might choose to optimize
away the order or th duplicates.

The compiler should process the expression [0...100, 50..75] depending on
the context.

if an expression if (a in [0...100, 50..75]) the compiler must recognize
that the second range can be optimized away so it emits

if (a>=0 && a<=100) {}

in a foreach loop like this:

foreach (int a in [0...100, 50..75])
{
Doit();
}

the compiler shall emit following code:

for (int i=0; i<=100; i++)
{
Doit();
}
for (int i=50; i<=75; i++)
{
Doit();
}

Note that the loop body will be duplicated, I have no better idea yet.
 
C

cody

I took "Unlike the C++ switch statement, C# does not support an explicit
It's fine - so long as you don't have code in between. You can do:

case 0:
case 1:
Foo();
break;

but you can't do:

case 0:
Foo();
case 1:
Bar();
break;


And I still cannot understand why they did it this way. Why not simply
automatically break each case and if you really need a fallthrough you would
have to use the keyword continue.

switch (a)
{
case 0: continue;
case 1: continue;
case 2:
Foo();
}

Why they favoured the least used case and not the most common one?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top