By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,930 Members | 1,389 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,930 IT Pros & Developers. It's quick & easy.

foreach enhancement

P: n/a
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
Nov 16 '05 #1
Share this Question
Share on Google+
104 Replies


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

--
William Stacey, MVP

"cody" <pl*************************@gmx.de> wrote in message
news:us**************@TK2MSFTNGP10.phx.gbl...
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


Nov 16 '05 #2

P: n/a

"William Stacey [MVP]" <st***********@mvps.org> wrote in message
news:uk**************@TK2MSFTNGP12.phx.gbl...
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" <pl*************************@gmx.de> wrote in message
news:us**************@TK2MSFTNGP10.phx.gbl...
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

Nov 16 '05 #3

P: n/a
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

--
Shak
(Houston)
"cody" <pl*************************@gmx.de> wrote in message
news:us**************@TK2MSFTNGP10.phx.gbl...
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

Nov 16 '05 #4

P: n/a
> 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.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #5

P: n/a

"cody" <pl*************************@gmx.de> wrote in message
news:%2******************@TK2MSFTNGP12.phx.gbl...
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.


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.
Nov 16 '05 #6

P: n/a
> > 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.
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 :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #7

P: n/a

"cody" <pl*************************@gmx.de> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
> 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.


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


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


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
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 :)


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

Nov 16 '05 #8

P: n/a
> 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.
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.


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
--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #9

P: n/a

"cody" <pl*************************@gmx.de> wrote in message
news:OT**************@TK2MSFTNGP09.phx.gbl...
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.


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


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.
Nov 16 '05 #10

P: n/a
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.
switch (a)
{
case 0..100: DoIt(); break;
}

Nov 16 '05 #11

P: n/a
cody wrote:
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
Nov 16 '05 #12

P: n/a
Paul Varjak 1961 <br*******@tiffanys.go.lightly> wrote:
Look up 'generics'

java has this already
Well, in beta...
c# will get in 2.0


What exactly do generics have to do with this? I can't see any
connection, myself.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #13

P: n/a
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?

"Michael C" <mi*******@optonline.net> wrote in message
news:MJ******************@news4.srv.hcvlny.cv.net. ..
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;
}

Nov 16 '05 #14

P: n/a
> 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]).
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.

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.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #15

P: n/a
> 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..

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #16

P: n/a
Daniel Billingsley <dbillingsley@NO_durcon_SPAAMM.com> wrote:
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;

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #17

P: n/a
cody <pl*************************@gmx.de> wrote:
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?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #18

P: n/a
> > > 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.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #19

P: n/a
> > 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;

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?

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #20

P: n/a
cody <pl*************************@gmx.de> wrote:
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) {}
So long as it doesn't affect the meaning, that's fine.
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.


Well, if it doesn't need to emit C#, only IL, there are more
alternatives...

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #21

P: n/a
cody <pl*************************@gmx.de> wrote:
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?


I'm not sure there's actually a need for a continue, to be honest.
Personally I'd have gone with just

case 0, 1, 2:
Foo();

and possibly allow multiple cases for readability:

case 0, 1, 2:
case 3, 4, 5:
Foo();

Any code between the cases (including an empty statement, just a semi-
colon) would make it a different case, so:

case 0, 1, 2:
;
case 3, 4, 5:
Foo();

would do nothing for 0, 1 or 2.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #22

P: n/a

"cody" <pl*************************@gmx.de> wrote in message
news:OU**************@TK2MSFTNGP09.phx.gbl...
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]).
> 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.

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.


As I said, I don't like every idea, but the cardinalities and a few other
bits are good ones. The entire featureset will almost certainly *not* make
it, however I wouldn't be surprised if little bits here adn there show up
over the next decade.
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.


Array literals are usually good because people don't like having to type new
type[] {1,3,5,6}, etc. I've heard quite a bit of fuss based entirely on not
likeing the existing inline array syntax, array literals gets around that.
If literal arrays can be considered immutable, the compiler could also do a
few optimizations, but thats more compliated than I want to get into.

Now, as far as foreach int i in 0...10000000) creating an array, I've been
thinking and I think I have a solution thats a little bit yours and a little
bit mine, namely generator expressions(for lack of a better term):

0...10 results in an expression of type IEnumerable
[expression] returns a list or array based off its content list, enumerating
enumerable values, so
[0...10] creates a list or array with the values 0-10, but 0...10 just
creates an iterator that generates the values 0-10

Its an interesting idea, however it leaves some problems. Discounting syntax
collisions, there are issues like with datetime above, without special
casing the datetime type, comparing between times would be *very* slow, as a
generator expression would have to generate a value for every tick. You
could use an increment clause but I'm not sure how to get that to work with
datetime without adding considerable complexity to the language(timespan
literals would help here, but they are rather rarely used things and
probably don't warrent addition).

The other option is to special case the in operator(or, as I'd rather do,
rename it to isin) as you suggested so that it doesn't emit the generator
expression, instead taking the values from it. This could be complicated to
do in situatinos like:

int lowerBound = 555;
int upperBound = 8137;
if (x isin [lowerBound...upperBound])

but I think it could be done.

For what its worth, isin would be an operator that takes a value x and
checks if it is in the list(or range) specified, returning a bool. It would
be able to stand alone, in other words
bool valid = 12 isin myNumberList;

such an operator would be required for functionality like this, IMHO.

The minimum requirements for ranges would probably have to be
T operator+(T,int) //Allow default increments, ie x...y where x and
y are T
T operator+(T,T) //Allow incrementing using T, ie x...y : z where
x, y, and z are T
bool operator==(T,T)
bool operator!=(T,T)
bool operator<(T,T)
bool operator>(T,T)
bool operator>=(T,T)
bool operator<=(T,T)
--
cody

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

Nov 16 '05 #23

P: n/a
> > 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.
Array literals are usually good because people don't like having to type

new type[] {1,3,5,6}, etc. I've heard quite a bit of fuss based entirely on not likeing the existing inline array syntax, array literals gets around that.
If literal arrays can be considered immutable, the compiler could also do a few optimizations, but thats more compliated than I want to get into.

Now, as far as foreach int i in 0...10000000) creating an array, I've been
thinking and I think I have a solution thats a little bit yours and a little bit mine, namely generator expressions(for lack of a better term):

Why not just making {1,2,3} an array literal? It is just a shorthand for new
int[]{1,2,3}.
The type is taken from the element literals, the compiler must just ensure
that all variables in the array literal have the same type.

0..10 is a set literal (or maybe "enumerable ordered set generator literal"
:) ).

So we can write if (a in 0..10) and we don't need the brackets.
if we have multiple ranges we can use parentheses: if (a in (0..10, 30..40))
0...10 results in an expression of type IEnumerable
[expression] returns a list or array based off its content list, enumerating enumerable values, so
[0...10] creates a list or array with the values 0-10, but 0...10 just
creates an iterator that generates the values 0-10

Its an interesting idea, however it leaves some problems. Discounting syntax collisions, there are issues like with datetime above, without special
casing the datetime type, comparing between times would be *very* slow, as a generator expression would have to generate a value for every tick.

We can simply that by default operator+(Type t, int n) is used for
increment.
If it is not present in the type we have to explicity state an increment
value.
This loop enumerates all days between today and the 31.12.2020 (we set the
increment to TimeSpan.TicksPerDay here)

foreach (DateTime dt in DateTime.Today..new DateTime(31,12,2020) :
TimeSpan.TicksPerDay ) {}
You could use an increment clause but I'm not sure how to get that to work with datetime without adding considerable complexity to the language(timespan
literals would help here, but they are rather rarely used things and
probably don't warrent addition).

The other option is to special case the in operator(or, as I'd rather do,
rename it to isin) as you suggested so that it doesn't emit the generator
expression, instead taking the values from it. This could be complicated to do in situatinos like:

int lowerBound = 555;
int upperBound = 8137;
if (x isin [lowerBound...upperBound])

What do you mean with that? Why do we need to rename "in" to "isin"?
For what its worth, isin would be an operator that takes a value x and
checks if it is in the list(or range) specified, returning a bool. It would be able to stand alone, in other words
bool valid = 12 isin myNumberList;
This gives me the idea that it should be possible to store such a set
literal in a variable. And which already existing keyword wouldn't fit
better:

set mySet = (1..10, 30..100);

if (a in mySet) {}
The minimum requirements for ranges would probably have to be
T operator+(T,int) //Allow default increments, ie x...y where x and y are T T operator+(T,T) //Allow incrementing using T, ie x...y : z where x, y, and z are T bool operator==(T,T)
bool operator!=(T,T)
bool operator<(T,T)
bool operator>(T,T)
bool operator>=(T,T)
bool operator<=(T,T)


I think we do not need operator!=(T,T). operator+(T,int) is only required if
no increment literal is specified and operator+(T,X) is only required if an
increment literal of type X is specified.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #24

P: n/a
> > 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?


I'm not sure there's actually a need for a continue, to be honest.
Personally I'd have gone with just

case 0, 1, 2:
Foo();

and possibly allow multiple cases for readability:

case 0, 1, 2:
case 3, 4, 5:
Foo();

Any code between the cases (including an empty statement, just a semi-
colon) would make it a different case, so:

case 0, 1, 2:
;
case 3, 4, 5:
Foo();

would do nothing for 0, 1 or 2.

This is great! It acually allows all thinkable cases without the need of any
keyword!
You certainly are the next candidate for the turing award in my eyes .)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #25

P: n/a
I actually looked it up on MS's website yesterday. The design team says
they forced a flow control statement after each case so that C++ programmers
wouldn't get confused by the lack of support for fall-through... Personally
I think anyone who has the brains to comprehend C++ code could probably
handle a slight change to the switch statement. LOL.

http://msdn.microsoft.com/vcsharp/te...h/default.aspx

Cheers,
Michael C.

"cody" <pl*************************@gmx.de> wrote in message
news:OD**************@TK2MSFTNGP12.phx.gbl...
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;

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?

--
cody

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

Nov 16 '05 #26

P: n/a

"cody" <pl*************************@gmx.de> wrote in message
news:eN**************@TK2MSFTNGP12.phx.gbl...
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.


Hmmm... would that give the correct result? You're performing the operation
127 times. Should the compiler optimize away the 50..75 so that it only
runs 101 times? I'm thinking of a situation like this:

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

This will give us 101 repititions because of the overlap at 50 using the
idea above; but the programmer may just be looking for 100 repititions in
this instance. Hmmm...

Cheers,
Michael C.
Nov 16 '05 #27

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Any code between the cases (including an empty statement, just a semi-
colon) would make it a different case, so:

case 0, 1, 2:
;
case 3, 4, 5:
Foo();

would do nothing for 0, 1 or 2.


And if you absolutely need a fall through, just use the current C# scheme
for fall through cases - namely the goto statement:

case 0, 1, 2:
FooBar();
goto case 3; // goto case 4 or goto case 5 would be equivalent in this
instance
//- the compiler will pick the target at compile so
it really doesn't matter
case 3, 4, 5:
Foo();

-----
By the way, I 'asked the designers' why they didn't include a short-hand
case statement like we've been discussing, and here's the response:

"We left the case syntax the way it was in C because we didn't see a big
reason to change it. While your suggestion is slightly more convenient, we
decided the difference wasn't big enough to warrant a change in syntax.

Similarly, on case ranges, we didn't see enough utility there to warrant
adding extra syntax, though we might revisit this decision at some time in
the future."

Cheers,
Michael C.
Nov 16 '05 #28

P: n/a
>

Why not just making {1,2,3} an array literal? It is just a shorthand for
new
int[]{1,2,3}.
Primarily because I'm concerned that {1,2,3} isn't syntactically possible.
{ <expression> } is legal syntax in C#(creates a block), how do you tell the
difference in that and {<listexpression>} ? Considering 10...30 as a
generator expression, { 10...30; } is ambigious outside of the ;, and I
don't particually care for distinguishing two very different syntaxes with a
single contained semicolon.
[] has no stand alone meaning I can think of, its tied to identifiers and
attributes, but I think it would be far more feasible to write a compiler
that works that way. Its certainly not guarenteed, but I think the chances
are better.

Attributes may throw some nasty bits into field assignments, I fear. One
could also probably use
<0...10> as well, but again I would have to experiment with a compiler to
know for sure.
The type is taken from the element literals, the compiler must just ensure
that all variables in the array literal have the same type.

0..10 is a set literal (or maybe "enumerable ordered set generator
literal"
:) ).

This does generate a set, I'll agree. However I think it fits better as a
sequence(or ordered set) generator instead of as a set expression\literal.
Instead of returning a "set", it returns an enumerator.
So we can write if (a in 0..10) and we don't need the brackets.
if we have multiple ranges we can use parentheses: if (a in (0..10,
30..40))
I'd rather write:
if (a in 0...30 || a in 30...40)

instead of adding extra parantheses. I worry about the compiler architecture
that would require(parentheses have specific meanings already, this would
overload them, which i'm always hesitant to do).


We can simply that by default operator+(Type t, int n) is used for
increment.
If it is not present in the type we have to explicity state an increment
value.
This loop enumerates all days between today and the 31.12.2020 (we set the
increment to TimeSpan.TicksPerDay here)

foreach (DateTime dt in DateTime.Today..new DateTime(31,12,2020) :
TimeSpan.TicksPerDay ) {}
This works pretty well, I have to admit. I didn't think of the various
TimeSpan values, although operator+(DateTime,TimeSpan) would be ideal in
this situation as well.
You could use an increment clause but I'm not sure how to get that to
work with
datetime without adding considerable complexity to the language(timespan
literals would help here, but they are rather rarely used things and
probably don't warrent addition).

The other option is to special case the in operator(or, as I'd rather do,
rename it to isin) as you suggested so that it doesn't emit the generator
expression, instead taking the values from it. This could be complicated

to
do in situatinos like:

int lowerBound = 555;
int upperBound = 8137;
if (x isin [lowerBound...upperBound])

What do you mean with that? Why do we need to rename "in" to "isin"?


Syntactic clarity, basically. in has a meaning.
Consider
foreach (x in y)
and
if (x in y)

in that case, in has two *very* different meanings in two *very* similar
situations. Using isin would skip that by creating a new keyword without
existing meaning in similar circumstances. things like default(which I don't
agree with, defaultof makes more sense) work because the usages are
different(default(x) and switch { default: break; } are very different.

I'm not advocating using isin in foreach, just as general containment
keyword.
For what its worth, isin would be an operator that takes a value x and
checks if it is in the list(or range) specified, returning a bool. It would
be able to stand alone, in other words
bool valid = 12 isin myNumberList;


This gives me the idea that it should be possible to store such a set
literal in a variable. And which already existing keyword wouldn't fit
better:


That requires definition of a new type, ISet, which we don't have yet.
However I wouldn't be terribly against the concept. Although a readonly
array would do the job fine. This however does lead back into the needs of
the general collections in the BCL.

Now, if you would *stop* insisting that it is a set literal and instead
consider it array or list literals, you don't need any additions,
IList\ICollection and Array do the job sufficently.
set mySet = (1..10, 30..100);
Again, parentheses wouldn't work here due to their existing meaning(grouping
expressions). Thats why I've proposed brackets a few times.

In this situation, however, you are forced to decide on ordered sets and on
lists. With lists you end up with two different sets of values added,
whereas if you are using sets you would use unions, etc instead. That would
clear up the need for parentheses here for a set

1...10 union 30...100 (can't think of a symbol for unions off hand).

Generator expressions could use set syntax while list literals could use
commas to seperate several list generators.

This does lead to the need of a set type, one that is defined by an equation
instead of by a literal and members are generated via an iterator as needed.

Sounds a bit functional, doesn't it.

if (a in mySet) {}
The minimum requirements for ranges would probably have to be
T operator+(T,int) //Allow default increments, ie x...y where x and y are T
T operator+(T,T) //Allow incrementing using T, ie x...y : z
where

x, y, and z are T
bool operator==(T,T)
bool operator!=(T,T)
bool operator<(T,T)
bool operator>(T,T)
bool operator>=(T,T)
bool operator<=(T,T)


I think we do not need operator!=(T,T). operator+(T,int) is only required
if
no increment literal is specified and operator+(T,X) is only required if
an
increment literal of type X is specified.


I agree on addition, standard adding rules works pretty well.

You have a point on !=, can't think of a use. However != is supposed to be
implemented when == is, so its required by default.
--
cody

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

Nov 16 '05 #29

P: n/a
Jon Skeet [C# MVP] wrote:
Paul Varjak 1961 <br*******@tiffanys.go.lightly> wrote:
Look up 'generics'

java has this already


Well, in beta...
c# will get in 2.0


What exactly do generics have to do with this? I can't see any
connection, myself.


http://www.ondotnet.com/pub/a/dotnet.../generics.html

You create a new set by specifying actual types to replace the formal
parameter:
using GCollections;
ISet<string> MyStringSet = new HashSet<string>();

This creates a set of strings, called MyStringSet. We can use this to write
a new variation on the classic first program. Note that we can use the C#
foreach construct even with a generic class defined in user code.
using GCollections;

class M {
public static void Main() {
ISet<string> MyStringSet = new HashSet<string>();
MyStringSet.Add("hello");
MyStringSet.Add("world");
foreach (string i in MyStringSet)
System.Console.WriteLine(i);
}
}

Nov 16 '05 #30

P: n/a
Sam Palmisamoo <im******@dam.it> wrote:
What exactly do generics have to do with this? I can't see any
connection, myself.


http://www.ondotnet.com/pub/a/dotnet.../generics.html

You create a new set by specifying actual types to replace the formal
parameter:
using GCollections;
ISet<string> MyStringSet = new HashSet<string>();

This creates a set of strings, called MyStringSet. We can use this to write
a new variation on the classic first program. Note that we can use the C#
foreach construct even with a generic class defined in user code.

using GCollections;

class M {
public static void Main() {
ISet<string> MyStringSet = new HashSet<string>();
MyStringSet.Add("hello");
MyStringSet.Add("world");
foreach (string i in MyStringSet)
System.Console.WriteLine(i);
}
}


That's hardly addressing the original question though. In particular,
there's no need for generics for any of that - you can use a Hashtable
today for set semantics, or an ArrayList for a sequence. Alternatively,
just create an array:

foreach (string i in new string[]{"hello", "world"})
{
....
}

My point is that generics doesn't actually do much for what cody's
after, which is a far more compact way of expressing sets and sequences
for use in foreach and if statements.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #31

P: n/a
Michael C <mi*******@optonline.net> wrote:
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.


Hmmm... would that give the correct result? You're performing the operation
127 times. Should the compiler optimize away the 50..75 so that it only
runs 101 times? I'm thinking of a situation like this:

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

This will give us 101 repititions because of the overlap at 50 using the
idea above; but the programmer may just be looking for 100 repititions in
this instance. Hmmm...


In that case the programmer is being foolish, in my view. If you ask
for two sequences which happen to share an endpoint, you should expect
to see the endpoint twice, IMO. I would be very confused if it *didn't*
give 101 iterations, personally.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #32

P: n/a
> I actually looked it up on MS's website yesterday. The design team says
they forced a flow control statement after each case so that C++ programmers wouldn't get confused by the lack of support for fall-through... Personally I think anyone who has the brains to comprehend C++ code could probably
handle a slight change to the switch statement. LOL.

http://msdn.microsoft.com/vcsharp/te...h/default.aspx

Hm very strange they must think programmers are stupid. If they let their
decisions lead by such thoughts, I'm surprised that they made it into
createing a new language at all.

Maybe it is the same with the private keyword. It is completly useless
because everything is private by default, but maybe they thought: "What if
C++ programmer will miss it?"

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #33

P: n/a
> > Why not just making {1,2,3} an array literal? It is just a shorthand for
new
int[]{1,2,3}.
Primarily because I'm concerned that {1,2,3} isn't syntactically possible.
{ <expression> } is legal syntax in C#(creates a block), how do you tell

the difference in that and {<listexpression>} ? Considering 10...30 as a
generator expression, { 10...30; } is ambigious outside of the ;, and I
don't particually care for distinguishing two very different syntaxes with a single contained semicolon.

We could simply say if a {} expression contains at least one semicolon or is
emtpy
then it is a codeblock, otherwise it is an array literal. An array literal
cannot be empty
(the compiler would not be able to determin the type) and is not allowed to
contain semicolons.

{ } // block
{ Foo(); } // block
{1} // array literal
{1,2} // array literal

Alternatively we can use the following facts to distinguish between them:
Array literals can never be used where also a block would be valid and vice
versa.

int[] a = {1,2}; // here only an array literal can be valid

Foo()
{
int a=0;
{ int a=0; } // here only a block can be valid
}

Foo({1,2}); // here it can be only an array literal

{1,2}.IndexOf(a); // methods cannot be called on a block which means it can
only be an array literal
[] has no stand alone meaning I can think of, its tied to identifiers and
attributes, but I think it would be far more feasible to write a compiler
that works that way. Its certainly not guarenteed, but I think the chances
are better.

Attributes may throw some nasty bits into field assignments, I fear. One
could also probably use
<0...10> as well, but again I would have to experiment with a compiler to
know for sure.

<0..10> Is a bad idea because it can have lots of meanings and is used in
generics too.
Additionally it doesn't look any beautiful :(

the braces are imho the best choice since they are already used to
initialize arrays
in c/c++ I can write: int[] a ={1,2}; so why not in c#?
What do you mean with that? Why do we need to rename "in" to "isin"?


Syntactic clarity, basically. in has a meaning.
Consider
foreach (x in y)
and
if (x in y)

in that case, in has two *very* different meanings in two *very* similar
situations. Using isin would skip that by creating a new keyword without
existing meaning in similar circumstances. things like default(which I

don't agree with, defaultof makes more sense) work because the usages are
different(default(x) and switch { default: break; } are very different.

I'm not advocating using isin in foreach, just as general containment
keyword.

I do not agree that we have to invent a new keyword.
A programmer will be able to distinguish between a foreach loop and a "if (a
in [1,2])" expression.
Most programming languages use one and the same keyword for different
purposes which is not bad imho.
This gives me the idea that it should be possible to store such a set
literal in a variable. And which already existing keyword wouldn't fit
better:


That requires definition of a new type, ISet, which we don't have yet.
However I wouldn't be terribly against the concept. Although a readonly
array would do the job fine. This however does lead back into the needs of
the general collections in the BCL.

Now, if you would *stop* insisting that it is a set literal and instead
consider it array or list literals, you don't need any additions,
IList\ICollection and Array do the job sufficently.

We can neither use IList nor Array since the set is readonly.
I think it doesn not need to be an object at all.
If we write foreach (int a in 0..10) the compiler just generates for (int
a=0;a<=10;i++) nothing more.
That would mean I cannot store the set into a variable but who cares.
Again, parentheses wouldn't work here due to their existing meaning(grouping expressions). Thats why I've proposed brackets a few times.

Agreed the brackets [] seems to be the best choice for set literals..

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #34

P: n/a

"cody" <pl*************************@gmx.de> wrote in message
news:eO**************@TK2MSFTNGP09.phx.gbl...
> Why not just making {1,2,3} an array literal? It is just a shorthand
> for
> new
> int[]{1,2,3}.
Primarily because I'm concerned that {1,2,3} isn't syntactically
possible.
{ <expression> } is legal syntax in C#(creates a block), how do you tell

the
difference in that and {<listexpression>} ? Considering 10...30 as a
generator expression, { 10...30; } is ambigious outside of the ;, and I
don't particually care for distinguishing two very different syntaxes
with

a
single contained semicolon.

We could simply say if a {} expression contains at least one semicolon or
is
emtpy
then it is a codeblock, otherwise it is an array literal. An array literal
cannot be empty
(the compiler would not be able to determin the type) and is not allowed
to
contain semicolons.


That shows that you have never written a compiler. Its not easy to determine
if a semicolon is contained within any given block as its handled by a
parser. { } // block
{ Foo(); } // block
{1} // array literal
{1,2} // array literal
what about
{
delegate(int x)
{
return 50;
}
}
?
Alternatively we can use the following facts to distinguish between them:
Array literals can never be used where also a block would be valid and
vice
versa.

int[] a = {1,2}; // here only an array literal can be valid

Foo()
{
int a=0;
{ int a=0; } // here only a block can be valid
}

Foo({1,2}); // here it can be only an array literal

{1,2}.IndexOf(a); // methods cannot be called on a block which means it
can
only be an array literal
[] has no stand alone meaning I can think of, its tied to identifiers and
attributes, but I think it would be far more feasible to write a compiler
that works that way. Its certainly not guarenteed, but I think the
chances
are better.

Attributes may throw some nasty bits into field assignments, I fear. One
could also probably use
<0...10> as well, but again I would have to experiment with a compiler to
know for sure.

<0..10> Is a bad idea because it can have lots of meanings and is used in
generics too.
Additionally it doesn't look any beautiful :(

the braces are imho the best choice since they are already used to
initialize arrays
in c/c++ I can write: int[] a ={1,2}; so why not in c#?


Because I think its too ambigious. C++ isn't the easiest langauge to write a
parser for, I imagine this is one of the major issues. I personally think
that using {'s is asking for extra compiler complexity without any real
benifits
> What do you mean with that? Why do we need to rename "in" to "isin"?
Syntactic clarity, basically. in has a meaning.
Consider
foreach (x in y)
and
if (x in y)

I do not agree that we have to invent a new keyword.
A programmer will be able to distinguish between a foreach loop and a "if
(a
in [1,2])" expression.
Most programming languages use one and the same keyword for different
purposes which is not bad imho.


A programmer *can*, but I think its...silly to force them to. The language
doesn't force that in any other situation.
Also, you *could* end up with
foreach (X x in GetIterator(x in [x1...x2]))
{
}

It'd be far easier to screw up the two meanings of in in this case, it just
isn't clean enough, IMHO.

I also think its rather short sighted to overload a keyword simply because
*other* langauges do it. One would ideally want to design the langauge so
its *right*, not nessecerily like others. I think overloading keywords for
the sake of overloading keywords is just not the right approach. A
minimization of keywords is a good idea, but I don't agree with the overkill
involved.
Now, if you would *stop* insisting that it is a set literal and instead
consider it array or list literals, you don't need any additions,
IList\ICollection and Array do the job sufficently.

We can neither use IList nor Array since the set is readonly.

Making the set read only is not definate. Nothing says it has to be.
Readonly is a seperate issue, it allows set interning, but isn't nessecery.
I think it doesn not need to be an object at all.
If we write foreach (int a in 0..10) the compiler just generates for (int
a=0;a<=10;i++) nothing more.
That would mean I cannot store the set into a variable but who cares.
In that case it doesn't, however if ranges are assignable for *other*
reasons, then it matters.

Again, parentheses wouldn't work here due to their existing meaning(grouping
expressions). Thats why I've proposed brackets a few times.

Agreed the brackets [] seems to be the best choice for set literals..


I agree, although I still think sets are not a nessecity. I'd rather see
list literals using [] instead of set literals. --
cody

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

Nov 16 '05 #35

P: n/a

"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:uV*************@TK2MSFTNGP11.phx.gbl...

"cody" <pl*************************@gmx.de> wrote in message
news:eO**************@TK2MSFTNGP09.phx.gbl...
> Why not just making {1,2,3} an array literal? It is just a shorthand
> for
> new
> int[]{1,2,3}.

Primarily because I'm concerned that {1,2,3} isn't syntactically
possible.
{ <expression> } is legal syntax in C#(creates a block), how do you tell

the
difference in that and {<listexpression>} ? Considering 10...30 as a
generator expression, { 10...30; } is ambigious outside of the ;, and I
don't particually care for distinguishing two very different syntaxes
with

a
single contained semicolon.

We could simply say if a {} expression contains at least one semicolon or
is
emtpy
then it is a codeblock, otherwise it is an array literal. An array
literal
cannot be empty
(the compiler would not be able to determin the type) and is not allowed
to
contain semicolons.


That shows that you have never written a compiler. Its not easy to
determine if a semicolon is contained within any given block as its
handled by a parser.
{ } // block
{ Foo(); } // block
{1} // array literal
{1,2} // array literal


what about
{
delegate(int x)
{
return 50;
}
}
?


Thinking about it a bit more, it may be possible using something
like(hopefullyu I got the syntax right, don't have a file open on hand)
array_literal_expression : OPEN_BRACKET expression_list CLOSE_BRACKET
;
expression_list
: expression
| expression_list expression
;

its worth looking into, I'll probably delve into mono again in a day or two
and see what can be done.
Nov 16 '05 #36

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
Hmmm... would that give the correct result? You're performing the operation 127 times. Should the compiler optimize away the 50..75 so that it only
runs 101 times? I'm thinking of a situation like this:

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

This will give us 101 repititions because of the overlap at 50 using the
idea above; but the programmer may just be looking for 100 repititions in this instance. Hmmm...


In that case the programmer is being foolish, in my view. If you ask
for two sequences which happen to share an endpoint, you should expect
to see the endpoint twice, IMO. I would be very confused if it *didn't*
give 101 iterations, personally.


So going back to the 'set' analogy, [1..50, 50..100] isn't a union of sets,
but rather shorthand for two separate sets?

Thanks,
Michael C
Nov 16 '05 #37

P: n/a

"Michael C" <mi******************************@getridofthis.com > wrote in
message news:k7********************@news4.srv.hcvlny.cv.ne t...

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...
> Hmmm... would that give the correct result? You're performing the operation > 127 times. Should the compiler optimize away the 50..75 so that it
> only
> runs 101 times? I'm thinking of a situation like this:
>
> foreach (int a in [1...50, 50..100])
> {
> Doit();
> }
>
> This will give us 101 repititions because of the overlap at 50 using
> the
> idea above; but the programmer may just be looking for 100 repititions in > this instance. Hmmm...
In that case the programmer is being foolish, in my view. If you ask
for two sequences which happen to share an endpoint, you should expect
to see the endpoint twice, IMO. I would be very confused if it *didn't*
give 101 iterations, personally.


So going back to the 'set' analogy, [1..50, 50..100] isn't a union of
sets,
but rather shorthand for two separate sets?


IMHO, its a set\list\array(thats being argued) generated from a pair of
sequence generator expressions. Its one item constructed out of two seperate
sequences, in other words. Consider each 1...n expression to be a generator,
short hand for a list of values between each. When wrapped in the [] syntax,
it would be the same as calling Add on the appropriate structure for each
value. For a *set*, you end up with 100 entries as the set can only contain
unique values(or you end up with an exception, thats a matter of
implementation), if [] syntax generates a list or an array, then you end up
with 101 entries, with 50 entered twice.

While I could see Jon being confused if that syntax generated a *list* with
a single instance of 50, I would be too. However, I'm sure he'd agree that
if it is two generators as the source for a *set* 50 would logically only
exist once. Odd as it is, the answer this question depends entirely on what
the actual semantics of the feature actually are.

Now, a set itself is probably not correct here as a set has no inherent
order and simply doesn't solve the problem. I think the syntax should
generate a list, and hence Jon and cody's examples are correct in their
behaviour.

This particular situation is something I would probably consider for a
warning. Code structured like that is strange and I would suspect rare
enough to consider "potentially erroneous". The compiler should issue a
warning like "List on line XXX generates duplicate values", which I think is
sufficent.
Thanks,
Michael C

Nov 16 '05 #38

P: n/a
Jon Skeet [C# MVP] wrote:

My point is that generics doesn't actually do much for what cody's
after, which is a far more compact way of expressing sets and sequences
for use in foreach and if statements.


This person seems to understand.
http://weblogs.asp.net/fmarguerie/ar.../10/36710.aspx
He talks about enums and sets, then goes on to mention how c# doesn't have
generics yet, which would be the more compact way to do what the OP wants.

He writes:

Just as a pretext, I tried to reproduce this behaviour in C#. We don't have
templates (oops, generics!) yet, so I went with code generation with
CodeSmith. The result is certainly not performant at all, but is an
interesting use of operator overloading and code generation.
Note that the result here is merely a simple collection and so very
different from Delphi's implementation of the concept!
I added however an implementation that works with flags enums (see the Flags
attribute) which allow enumerations to be treated as bit fields. This is
closer to what Delphi does and certainly more performant.
Nov 16 '05 #39

P: n/a
Michael C <mi******************************@getridofthis.com > wrote:
In that case the programmer is being foolish, in my view. If you ask
for two sequences which happen to share an endpoint, you should expect
to see the endpoint twice, IMO. I would be very confused if it *didn't*
give 101 iterations, personally.


So going back to the 'set' analogy, [1..50, 50..100] isn't a union of sets,
but rather shorthand for two separate sets?


When used in a foreach statement, it shouldn't be regarded as a set at
all - it should be regarded as a sequence, IMO.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #40

P: n/a
Czhen du Loc Pha <cd**@vietname.du.spam> wrote:
My point is that generics doesn't actually do much for what cody's
after, which is a far more compact way of expressing sets and sequences
for use in foreach and if statements.
This person seems to understand.


Well, I'd say he seems to understand that generics will provide an
easier way of creating type-safe sets. That's not the same as providing
extra syntax in the language to make them *really* easy, as cody was
requesting.
http://weblogs.asp.net/fmarguerie/ar.../10/36710.aspx

He talks about enums and sets, then goes on to mention how c# doesn't have
generics yet, which would be the more compact way to do what the OP wants.


He doesn't claim that generics are going to change the language in the
way suggested by cody, however.

Sure, type-safe sets themselves will be easier to write when we've got
generics - but they aren't going to make it possible to write

foreach (int i in [1..50, 50..100])

The original post I replied to in this subthread seemed to imply that
generics would provide the answer to cody's original request. They
won't.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #41

P: n/a
> So going back to the 'set' analogy, [1..50, 50..100] isn't a union of
sets,
but rather shorthand for two separate sets?

It is a list of ranges to be precise. The term "set" seems indeed not
correct for that construct.
The ranges might overlap, and a foreach iterates over *all* values in the
set/list/whatever in the order they appear in the declaration. if used in if
(a in [1..50, 50..100]) the compiler should optimize away duplicates.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #42

P: n/a
> >>> > Why not just making {1,2,3} an array literal? It is just a shorthand
> for
> new
> int[]{1,2,3}.

Primarily because I'm concerned that {1,2,3} isn't syntactically
possible.
{ <expression> } is legal syntax in C#(creates a block), how do you tell the
difference in that and {<listexpression>} ? Considering 10...30 as a
generator expression, { 10...30; } is ambigious outside of the ;, and I don't particually care for distinguishing two very different syntaxes
with
a
single contained semicolon.
We could simply say if a {} expression contains at least one semicolon or is
emtpy
then it is a codeblock, otherwise it is an array literal. An array
literal
cannot be empty
(the compiler would not be able to determin the type) and is not allowed to
contain semicolons.

That shows that you have never written a compiler. Its not easy to
determine if a semicolon is contained within any given block as its
handled by a parser.
{ } // block
{ Foo(); } // block
{1} // array literal
{1,2} // array literal


what about
{
delegate(int x)
{
return 50;
}
}
?


Thinking about it a bit more, it may be possible using something
like(hopefullyu I got the syntax right, don't have a file open on hand)
array_literal_expression : OPEN_BRACKET expression_list CLOSE_BRACKET
;
expression_list
: expression
| expression_list expression
;

its worth looking into, I'll probably delve into mono again in a day or

two and see what can be done.

That would be very great :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #43

P: n/a
> >>> > Why not just making {1,2,3} an array literal? It is just a shorthand
> for
> new
> int[]{1,2,3}.

Primarily because I'm concerned that {1,2,3} isn't syntactically
possible.
{ <expression> } is legal syntax in C#(creates a block), how do you tell the
difference in that and {<listexpression>} ? Considering 10...30 as a
generator expression, { 10...30; } is ambigious outside of the ;, and I don't particually care for distinguishing two very different syntaxes
with
a
single contained semicolon.
We could simply say if a {} expression contains at least one semicolon or is
emtpy
then it is a codeblock, otherwise it is an array literal. An array
literal
cannot be empty
(the compiler would not be able to determin the type) and is not allowed to
contain semicolons.

That shows that you have never written a compiler. Its not easy to
determine if a semicolon is contained within any given block as its
handled by a parser.
{ } // block
{ Foo(); } // block
{1} // array literal
{1,2} // array literal


what about
{
delegate(int x)
{
return 50;
}
}
?


Thinking about it a bit more, it may be possible using something
like(hopefullyu I got the syntax right, don't have a file open on hand)
array_literal_expression : OPEN_BRACKET expression_list CLOSE_BRACKET
;
expression_list
: expression
| expression_list expression
;

its worth looking into, I'll probably delve into mono again in a day or

two and see what can be done.

With brackets[] you mean braces{} don't you?

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #44

P: n/a

Thinking about it a bit more, it may be possible using something
like(hopefullyu I got the syntax right, don't have a file open on hand)
array_literal_expression : OPEN_BRACKET expression_list CLOSE_BRACKET
;
expression_list
: expression
| expression_list expression
;

its worth looking into, I'll probably delve into mono again in a day or two
and see what can be done.

With brackets[] you mean braces{} don't you?

Yes, I think that the mono parser calls { OPEN_BRACKET, but I could be
wrong. I forget what [ is identified as.
Some of the names in that parser are a little strange.

Heres my plan for the moment, let me know what you think:

1) m...n is a range generator. It returns am IEnumerable. It can be assigned
to any IEnumerable variable or used as IEnumerable in foreach or as a method
parameter.
2) [<enumerableExpression>,<literalExpression>,<source Expression>] generates
an IList containing those values.
2b) Lists take the best possible type. If your enumerable expression returns
int and you have a long literal, the list is IList<long>, if it returns ints
and you have a double literal, IList<double>, etc. If the list contains
heterogeneous types, such as int and string or int and date time, it is
typed as IList<object>. I still have to consider the exact rules of such.
3) {<enumerableExpression>,<literalExpression>,<sourc eExpression>] generates
an array containing those values.
3b) For arrays all values have to be of the same type. Array literals take
on the numeric behaviour where the largest nessecery type is used, but
arrays cannot contain multiple types.
4) For enumerableExpression, every value is read out *unless* the expression
is cast to object or somesuch. This does leave a problem in that there is no
way to generate a list of IEnumerables, but if someone wants that edge case
they should probably use long-hand list or array syntax. Can you think of
any workarounds for this?
enumerableExpression is typed either object for IEnumerable or T for
IEnumerable<T>.
5) sourceExpression is any expression that returns a type, be it
mathematical or a method call. These aren't literals in a very strict sense,
every one of these values is generated at run time(unless compiletime
generation is possible).
6) Where possible, foreach over a list or generator will generate a for
loop. This will only occur if the list generates integers or other
structures that support > <, etc. If the compiler cannot determine a valid
for loop or if code complexity would become to great(too many ranges or
multiple types), the compiler will instead generate the list and foreach
will operate over that lists IEnumerable implementation.
7) Valid range increment values are *any* value the range type has a
operator+ defined for. The operator+ must return the range type however.
8) For contains checking, I'm still much more comfortable with isin over in,
so I will likely implement that keyword as it stands. However I will
consider adding a pragma that changes support to in so that eitehr can be
experimented with.

9) Experimental: If code contains the same range type twice only one
IEnumerable\IEnumerator class pair will be generated. That pair will take
parameters that determine ranges. This should cut down on class bloat

Well, thats a basic outline for what I'll do(assuming I can find time). Any
comments from anyone?
--
cody

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

Nov 16 '05 #45

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP************************@msnews.microsoft.c om...

So going back to the 'set' analogy, [1..50, 50..100] isn't a union of sets, but rather shorthand for two separate sets?


When used in a foreach statement, it shouldn't be regarded as a set at
all - it should be regarded as a sequence, IMO.


OK, this is purely hypothetical, so bear with me and be kind if I'm Wayyyyy
off base:

The overloaded brackets are confusing. Would it be possible to create a new
Sequence class that extends the Collection class, overloads the "+" operator
to act as a join on the sequences, and takes advantage of the IEnumerator
interface for foreach operations? Example:

foreach (int a in Sequence(1, 50) + Sequence(25, 100)) // + operator
overloaded to "join" the 2

// sequences, with overlap so would return

// 1..50, 25..100

Maybe we could use params in the constructor to implement a constructor that
allows us to create multiple Sequences at once?

foreach (int a in Sequence(1, 50, 25, 100)) // creates two sequences, 1..50
and 25..100 and
// joins
them into one for us with overlap; shorthand for +

This has the additional advantage of letting us create dynamic sequences
using variables (not just constants) on the fly:

int x = 1;
int y = 50;
foreach (int a in new Sequence (x, y))

Finally, if we feel it's necessary we can overload the other operators.
Here's a suggestion:

Sequence(1, 50) - Sequence(3, 8) // subtracts or removes a sequence. would
give us 1..2, 9..50
Sequence(1, 50) * Sequence (25, 75) // as opposed to +, this would give us a
union with no overlaps. this
// would be a
'combine' operation as opposed to an
// overlapping
join so would return 1..75

Just a thought.

Thanks,
Michael C.
Nov 16 '05 #46

P: n/a
> OK, this is purely hypothetical, so bear with me and be kind if I'm
Wayyyyy
off base:

The overloaded brackets are confusing. Would it be possible to create a new Sequence class that extends the Collection class, overloads the "+" operator to act as a join on the sequences, and takes advantage of the IEnumerator
interface for foreach operations? Example:

foreach (int a in Sequence(1, 50) + Sequence(25, 100)) // + operator
overloaded to "join" the 2

// sequences, with overlap so would return

// 1..50, 25..100

Maybe we could use params in the constructor to implement a constructor that allows us to create multiple Sequences at once?

foreach (int a in Sequence(1, 50, 25, 100)) // creates two sequences, 1..50 and 25..100 and
// joins
them into one for us with overlap; shorthand for +

This has the additional advantage of letting us create dynamic sequences
using variables (not just constants) on the fly:

int x = 1;
int y = 50;
foreach (int a in new Sequence (x, y))

Finally, if we feel it's necessary we can overload the other operators.
Here's a suggestion:

Sequence(1, 50) - Sequence(3, 8) // subtracts or removes a sequence. would give us 1..2, 9..50
Sequence(1, 50) * Sequence (25, 75) // as opposed to +, this would give us a union with no overlaps. this
// would be a
'combine' operation as opposed to an
// overlapping
join so would return 1..75


This would all certainly be possible, without any problem. Such a sequence
class can be written in half an hour, but that is not the point here. The
idea was to invent a new language feature which allow the programmer to loop
over multiple ranges and test wheather a value exists in a range with a
simple built in syntax and *without* creating any temporary objects.

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #47

P: n/a

"cody" <pl*************************@gmx.de> wrote in message
news:ef**************@tk2msftngp13.phx.gbl...

This would all certainly be possible, without any problem. Such a sequence
class can be written in half an hour, but that is not the point here. The
idea was to invent a new language feature which allow the programmer to loop over multiple ranges and test wheather a value exists in a range with a
simple built in syntax and *without* creating any temporary objects.


Ahh, I thought the point was to be able to create sequences that would allow
you to iterate over all members of the sequence/range, or multiple
sequences/ranges, using foreach.

I didn't realize the only acceptable option was a language re-design. I
suppose I don't see the benefit of changing the language syntax in order to
accomplish something that can be done in half an hour.

Best of luck with that.

Thanks,
Michael C.
Nov 16 '05 #48

P: n/a
> Heres my plan for the moment, let me know what you think:

1) m...n is a range generator. It returns am IEnumerable. It can be assigned to any IEnumerable variable or used as IEnumerable in foreach or as a method parameter.
2) [<enumerableExpression>,<literalExpression>,<source Expression>] generates an IList containing those values.
2b) Lists take the best possible type. If your enumerable expression returns int and you have a long literal, the list is IList<long>, if it returns ints and you have a double literal, IList<double>, etc. If the list contains
heterogeneous types, such as int and string or int and date time, it is
typed as IList<object>. I still have to consider the exact rules of such.
3) {<enumerableExpression>,<literalExpression>,<sourc eExpression>] generates an array containing those values.
3b) For arrays all values have to be of the same type. Array literals take
on the numeric behaviour where the largest nessecery type is used, but
arrays cannot contain multiple types.
We also could say that for objects we make the array of a type that is
common base class of *all* of the array members and supports all interfaces
which *all* objects in the array support:

{string, object} // array type is object
{IList, Array} // array type if object supporting IList
{Control, TextBox} // array type is Control

If the array contains value types *and* reference types, the type of the
array is object.
If only numeric types are involved I agree that the array should be of the
type of the biggest nessecary numeric type.
4) For enumerableExpression, every value is read out *unless* the expression is cast to object or somesuch. This does leave a problem in that there is no way to generate a list of IEnumerables, but if someone wants that edge case they should probably use long-hand list or array syntax. Can you think of
any workarounds for this?
enumerableExpression is typed either object for IEnumerable or T for
IEnumerable<T>.
I do not like that Idea. It would mean that you cannot put any object
supporting IEnumerable into the array without splitting it up into its
items. Better would be IEnumerator instead of IEnumerable, which means
you'll have to put list.GetEnumerator() into the array so it'll be splitted
up. But I still do not like that idea. Array have a fixed size and allowing
IEnumerators to be inserted into array literals means that during runtime
you have to create temporary lists and copy from them into the destination
array since you cannot resize it.
e.g:

{obj1, obj2, list1}

Assumed you want to guarantee that the expressions are evaluated in the
order they appear in the declaration you have first to create a temporary
list. you put obj1 and obj2 in it. then you have to evaluate list1 and add
its contents to the list. after you've evaluated all objects you can call
..ToArray() and your array is constructed.
But again, I do not like the idea of expanding IEnumerables. If I declare an
array literal containg 3 elements I expect that is really has 3 elements and
not more.
5) sourceExpression is any expression that returns a type, be it
mathematical or a method call. These aren't literals in a very strict sense, every one of these values is generated at run time(unless compiletime
generation is possible).
agreed.
6) Where possible, foreach over a list or generator will generate a for
loop. This will only occur if the list generates integers or other
structures that support > <, etc. If the compiler cannot determine a valid
for loop or if code complexity would become to great(too many ranges or
multiple types), the compiler will instead generate the list and foreach
will operate over that lists IEnumerable implementation.
You are talking about set literals now? We should clearly separate the short
array literal syntax and the multi-range-set-literal syntax, they have
nothing to do with each other.
7) Valid range increment values are *any* value the range type has a
operator+ defined for. The operator+ must return the range type however.
agreed.
8) For contains checking, I'm still much more comfortable with isin over in, so I will likely implement that keyword as it stands. However I will
consider adding a pragma that changes support to in so that eitehr can be
experimented with.
I do not agree but you are the one who implements it :)
9) Experimental: If code contains the same range type twice only one
IEnumerable\IEnumerator class pair will be generated. That pair will take
parameters that determine ranges. This should cut down on class bloat


Good idea. The bad thing is that generics do not support operator
overloading which means we cannot use generics here and we must create a new
class for each type.

However, I still think that it is still possible to implement this
sets/ranges without the creation of any classes/objects. It will maybe make
the implemention harder but will make the code faster and do not need
temporary objects and a bloat of classes.

"if (a in [0..100, 200..300])" should only be a substitute of
"if ((a>=0&&a<=100)||(a>=200&&a<=300))",

and "foreach (a in 0..100, 200,300)" should simply be compiled to
"for (int a=0;a<=100;a++){} for (int a=200;a<=300;a++){}"

But this is only implementation detail, no programmer using the language
should be affected on how it is implemented.
A simply implementation as a proof of concept should be enough for now and
hopefully our ideas will make it into regular c# someday :)

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #49

P: n/a
> > This would all certainly be possible, without any problem. Such a
sequence
class can be written in half an hour, but that is not the point here. The idea was to invent a new language feature which allow the programmer to loop
over multiple ranges and test wheather a value exists in a range with a
simple built in syntax and *without* creating any temporary objects.


Ahh, I thought the point was to be able to create sequences that would

allow you to iterate over all members of the sequence/range, or multiple
sequences/ranges, using foreach.
Indeed, that was the point.
I didn't realize the only acceptable option was a language re-design. I
suppose I don't see the benefit of changing the language syntax in order to accomplish something that can be done in half an hour.


You'll agree, that foreach (a in 1..100, 200..300) is far better than

foreach (a in SequenceBuilder.GetSequence(1, 100) +
SequenceBuilder.GetSequence(200, 300))

don't you? And exactly that is the purpose of my proposal.
Loops are one of the most common used things and making them more readable
and maintainable should be a desirable goal, don't you agree?

Using the syntax I proposed, the compiler will be able to substitute the
foreach loop to a normal
for loop so you won't have any performance penalty and there is no need for
creating additional classes and temporary objects.

I encourage you to read the whole thread to understand how these constructs
can improve code quality (we are not only talking about foreach loops here).

--
cody

[Freeware, Games and Humor]
www.deutronium.de.vu || www.deutronium.tk
Nov 16 '05 #50

104 Replies

This discussion thread is closed

Replies have been disabled for this discussion.