473,698 Members | 2,662 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

[Feature Request] "first:" "last:" sections in a "foreach" block

I'd like to make the following proposal for a new feature for the C#
language. I have no connection with the C# team at Microsoft. I'm posting
it here to gather input to refine it, in an "open Source" manner, and in an
attempt to build a ground-swell of support to convince the folks at
Microsoft to add it.
Proposal: "first:" "last:" sections in a "foreach" block

The problem:
The foreach statement allows iterating over all the elements of a
collection. However, often the first or last element of the collection must
be handled differently than the others in the collection. For example, if
we were generating a list of items for display, we'd want a comma after
every item except the last. In these cases, foreach cannot be used, and the
alternates which can be used are generally ugly and often less efficient
than foreach. An elegant solution keeping with the concept of C# is needed.

The proposal:
I suggest adding four new keywords (only available inside foreach block) to
direct the compiler to our exact intentions. "first:" "last:" "other:"
"all:"

Example:
foreach (Person p in personCollectio n)
{
first:
Console.WriteLi ne("Names: {0},", p.Name");
other:
Console.WriteLi ne(" {0},", p.Name");
last:
Console.WriteLi ne(" {0}", p.Name");
}
A block not preceeded by one of those keywords would be assumed to be an
"all:" block, exact as is the case now.

Analysis:
The advantages of the feature:
It solves a problem in an elegant way, keeping with the design concepts of
C#.
It is handled entirely by the compiler, so that it has ZERO effect on code
that does not use it, and it requires no changes to the class framework or
the CLR. (These were problems with other suggested solutions for this)

The disadvantages:
It requires four keywords, although this could be reduced to three
(eliminating "all:") and, they would each be very context sensitive, so the
conflicts with user-defined identifiers is unlikely.

Implementation:
Presently, a foreach construct is largely "syntactic sugar" around a while
loop using an IEnumerator, such that code written as
foreach (int i in arry)
{
Console.WriteLi ne(i);
}

Would be compiled much as if it were written:
IEnumerator n = arry.GetEnumera tor();
while(n.MoveNex t())
{
int i = (int) n.Current;
Console.WriteLi ne(i);
}

Similarly, code using these blocks would also have a direct translation:
foreach (int i in arry)
{
First:
Console.WriteLi ne("{0} - first", i);
Others:
Console.WriteLi ne(i);
}

Would be compiled as:
IEnumerator n = arry.GetEnumera tor();
if (n.MoveNext())
{
int i = (int) n.Current;
Console.WriteLi ne("{0}-- first ", i);
while(n.MoveNex t())
{
i = (int) n.Current;
Console.WriteLi ne(i);
}
}
(The internal representation of a "last:" block is a bit more involved, but
still basically straightforward )

Any comments are suggestion would be appreciated.

Truth,
James Curran
MVP (for .um. VC++)

Nov 16 '05
32 4137
"C# Learner" <cs****@learner .here> wrote in message
news:%2******** ********@TK2MSF TNGP09.phx.gbl. ..
I've got a feeling that people in general might prefer something like
the following, though:

foreach (Person p in personCollectio n)
{
first
{
Console.WriteLi ne("Names: {0},", p.Name");
}
other [snip] }


Actually, as I originally planned the original post, I had intended a
section for "possible alternate syntaxes" which included that as well as
Daniel's "case" syntax. Unfortunately, as I was writing at 4AM, some parts
had to be pared out in the hopes of getting some sleep. But I'm not married
to any particular syntax, and open to all suggestions.

Truth,
James Curran
Nov 16 '05 #11
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:%2******** ********@TK2MSF TNGP10.phx.gbl. ..
I prefer case or another context sensitive keyword myself. case first;case
last;case index 2; case index 5;case index default;case all may work and
wouldn't cause existing code to fail.


The use of "case first" et al was to be in a section of "alternate syntaxes"
which got inadvertantly dropped from the original post.

However "case index 2:" poses problems because presently the IEnumerator
doesn't store the index value, whidch means to implement it, we'd have to
increase the size of every IEnumerator object (to store the index), and
increase the work done by IEnumerator.Mov eNext (to update the index), which,
well, breaks everything currently using IEnumerator. This very issue was
dealt with by Raymond Chen of MSFT in this blog
http://dotnetjunkies.com/WebLog/d0m1....aspx#FeedBack.
I should note that this proposal grew out of that Blog entry by Dominic
Morris, which attracted comments from several MSFT employee, and was written
in light of their comments.

Truth,
James Curran
Nov 16 '05 #12
Daniel O'Connell [C# MVP] <onyxkirx@--NOSPAM--comcast.net> wrote:
Thats IEnumerable actually.
Oops, yes.
While IEnumerator has the same suggestion, I
think its a touch irresponsible to define an IEnumerator as working in any
order. The semantics of IEnumerable, espeically when working with IList,
suggest to me that natural order should be used when available and no
documentation says otherwise, but a given IEnumerator should not be
constrained in its design by any specification(A lthough that is pretty moot
considering foreach can't handle IEnumerator directly, unfortunatly).
I would agree that it's not really the place of IEnumerable/IEnumerator
to define the order. IList.GetEnumer ator should do it, in my view - the
MSDN is unfortunate in not tending to define the meaning of overridden
methods in the overriding classes any more than the base
class/interface does :(
Its picky, I know, but I consider the difference between the two an
important point that MSDN and C# to an extent doesn't really illustrate
well.


Sure - and well spotted.

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

"James Curran" <Ja*********@mv ps.org> wrote in message
news:%2******** ********@TK2MSF TNGP12.phx.gbl. ..
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:%2******** ********@TK2MSF TNGP10.phx.gbl. ..
I prefer case or another context sensitive keyword myself. case
first;case
last;case index 2; case index 5;case index default;case all may work and
wouldn't cause existing code to fail.
The use of "case first" et al was to be in a section of "alternate
syntaxes"
which got inadvertantly dropped from the original post.


Syntax is always the hard part. I think I like case <lable> more than I like
the foreach.first syntax suggested in that post.


However "case index 2:" poses problems because presently the IEnumerator
doesn't store the index value, whidch means to implement it, we'd have to
increase the size of every IEnumerator object (to store the index), and
increase the work done by IEnumerator.Mov eNext (to update the index),
which,
well, breaks everything currently using IEnumerator. This very issue was
dealt with by Raymond Chen of MSFT in this blog
http://dotnetjunkies.com/WebLog/d0m1....aspx#FeedBack.
I should note that this proposal grew out of that Blog entry by Dominic
Morris, which attracted comments from several MSFT employee, and was
written
in light of their comments.

I don't think it would need to be done by modifying IEnumerator. Like Eric
Gunnerson points out,

int index = 0;
foreach (string s in list)
{
if (index++ == 0)
{
// do something special here
}
}

would do it. Instead of producing an explicit variable, I would instead let
the compiler generate a temporary and use the case index X syntax to match
against that value. Ideally the compiler would only generate the temp and
bother with that *if* a case index existed within the foreach block. I would
argue against the need for an index available in the foreach as a feature on
its own, but support like you suggest here would be reason enough to
logically extend the system to provide index casing. Truth,
James Curran

Nov 16 '05 #14

"Julie" <ju***@nospam.c om> wrote in message
news:40******** *******@nospam. com...
James Curran wrote:
The problem:
The foreach statement allows iterating over all the elements of a
collection. However, often the first or last element of the collection
must
be handled differently than the others in the collection. For example,
if
we were generating a list of items for display, we'd want a comma after
every item except the last. In these cases, foreach cannot be used, and
the
alternates which can be used are generally ugly and often less efficient
than foreach. An elegant solution keeping with the concept of C# is
needed.


I don't disagree that there could be some potential benefit.

However, in the case that you state, it is relatively simple to handle
this
case:

String output = "Names: ";
foreach (String name in names)
{
output += name + ",";
}
output.TrimEnd( ",");
Console.WriteLi ne(output);

Which in my opinion is pretty readable.

I think that the biggest problem is the last: case. During enumeration,
the
last element isn't determinable until you are past the end, and therefore
would
impose more requirements on collections.


It is harder to do but not impossible. Consider

foreach (char x in "Mouse")
{
case first: Console.WriteLi ne("First: " + x);
case last: Console.WriteLi ne("Last: " + x);
case other: Console.WriteLi ne("Middle: " + x);

}

The compiler could translate it into something like:

IEnumerator enumerator = ((IEnumerable)" Mouse").GetEnum erator();
enumerator.Move Next();
//first
char x = (char)enumerato r.Current;
Console.WriteLi ne("First: " + x);
//end first
if (enumerator.Mov eNext())
{
while (true)
{
x = (char)enumerato r.Current;
//other
if (enumerator.Mov eNext() == false)
break;
Console.WriteLi ne("Middle: " + x);
//end other
}
//last
Console.WriteLi ne("Last: " + x);
}

which results in

First: M

Middle: o

Middle: u

Middle: s

Last: e

The real question is where does "all" fit in. Should it exectue before or
after a given case?
Nov 16 '05 #15
Hi James,

Thanks very much for your suggestion.

I have viewed it, and I think it really makes sense. I suggest you provide
your suggestion to:
http://register.microsoft.com/mswish/suggestion.asp

Also, I will forward your suggestion to our product group. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.

Nov 16 '05 #16
I would think that by the definition of foreach, the language construct
is unable to predict the size of the enumerable in question. Which would
mean that the foreach loop would need to read-ahead to determine the
ordinality of the enumerable list. IMHO that would make the whole
foreach inefficient would'nt you say?

James Curran wrote:
I'd like to make the following proposal for a new feature for the C#
language. I have no connection with the C# team at Microsoft. I'm posting
it here to gather input to refine it, in an "open Source" manner, and in an
attempt to build a ground-swell of support to convince the folks at
Microsoft to add it.
Proposal: "first:" "last:" sections in a "foreach" block

The problem:
The foreach statement allows iterating over all the elements of a
collection. However, often the first or last element of the collection must
be handled differently than the others in the collection. For example, if
we were generating a list of items for display, we'd want a comma after
every item except the last. In these cases, foreach cannot be used, and the
alternates which can be used are generally ugly and often less efficient
than foreach. An elegant solution keeping with the concept of C# is needed.

The proposal:
I suggest adding four new keywords (only available inside foreach block) to
direct the compiler to our exact intentions. "first:" "last:" "other:"
"all:"

Example:
foreach (Person p in personCollectio n)
{
first:
Console.WriteLi ne("Names: {0},", p.Name");
other:
Console.WriteLi ne(" {0},", p.Name");
last:
Console.WriteLi ne(" {0}", p.Name");
}
A block not preceeded by one of those keywords would be assumed to be an
"all:" block, exact as is the case now.

Analysis:
The advantages of the feature:
It solves a problem in an elegant way, keeping with the design concepts of
C#.
It is handled entirely by the compiler, so that it has ZERO effect on code
that does not use it, and it requires no changes to the class framework or
the CLR. (These were problems with other suggested solutions for this)

The disadvantages:
It requires four keywords, although this could be reduced to three
(eliminating "all:") and, they would each be very context sensitive, so the
conflicts with user-defined identifiers is unlikely.

Implementation:
Presently, a foreach construct is largely "syntactic sugar" around a while
loop using an IEnumerator, such that code written as
foreach (int i in arry)
{
Console.WriteLi ne(i);
}

Would be compiled much as if it were written:
IEnumerator n = arry.GetEnumera tor();
while(n.MoveNex t())
{
int i = (int) n.Current;
Console.WriteLi ne(i);
}

Similarly, code using these blocks would also have a direct translation:
foreach (int i in arry)
{
First:
Console.WriteLi ne("{0} - first", i);
Others:
Console.WriteLi ne(i);
}

Would be compiled as:
IEnumerator n = arry.GetEnumera tor();
if (n.MoveNext())
{
int i = (int) n.Current;
Console.WriteLi ne("{0}-- first ", i);
while(n.MoveNex t())
{
i = (int) n.Current;
Console.WriteLi ne(i);
}
}
(The internal representation of a "last:" block is a bit more involved, but
still basically straightforward )

Any comments are suggestion would be appreciated.

Truth,
James Curran
MVP (for .um. VC++)


--
Regards,
Dilip Krishnan
MCAD, MCSD.net
dilipdotnet at apdiya dot com
Nov 16 '05 #17
Dilip Krishnan <dilipdotnet..N OSPAM..@apdiya. com> wrote:
I would think that by the definition of foreach, the language construct
is unable to predict the size of the enumerable in question. Which would
mean that the foreach loop would need to read-ahead to determine the
ordinality of the enumerable list. IMHO that would make the whole
foreach inefficient would'nt you say?


You don't need to know the ordinality though - you only need to know
first or last. First is obvious, and the "last" bit you just execute
when the next MoveNext returns false (or whatever - I can't remember
the exact interface offhand). It would be slightly trickier to make the
"last" case not also execute "other", and it would be easier to
basically make that something executed *as well as* the "other" case,
but other than that it's not tricky.

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

foreach means foreach means foreach, so for each item of a collection of
items do this. I would not like to see a switch inside the loop that test
for the first or the last or whichever item. It conflicts with what I
learned long time ago about loop-unrolling and its effect.

Instead, I would like to state foreach item in this (not that) collection do
this, this collection excluding the first and last item for example, in
other words, I would like to be able to more precisely define the items for
which I want some code to execute. It could be that I want to execute this
for every other item and that for all the others.

What about something along these lines where I would be able to define a
part of the collection of items? A bit like string.substrin g and similar
constructs.

foreach(item in items[2,8])

or

foreach(item in items[2,])

or like the Python splice thingy?

The suggestion I like, meaning a way to more precisely define which items to
execute code for. Syntax and semantics are another thing.

Can't this be done already I wonder...



Nov 16 '05 #19

"Joep" <St***@DeStoep. nl> wrote in message
news:40******** *************@n ews.xs4all.nl.. .
IMHO

foreach means foreach means foreach, so for each item of a collection of
items do this. I would not like to see a switch inside the loop that test
for the first or the last or whichever item. It conflicts with what I
learned long time ago about loop-unrolling and its effect.

Instead, I would like to state foreach item in this (not that) collection
do
this, this collection excluding the first and last item for example, in
other words, I would like to be able to more precisely define the items
for
which I want some code to execute. It could be that I want to execute this
for every other item and that for all the others.

What about something along these lines where I would be able to define a
part of the collection of items? A bit like string.substrin g and similar
constructs.

foreach(item in items[2,8])

or

foreach(item in items[2,])

or like the Python splice thingy?
A few problems with this.

Order returned by an enumerator is only statically defined during the
lifetime of the enumerator. There is nothing that requires two sequential
executions of foreach over the same object to actually process the items in
the same order(or really that IEnumerator isn't strictly required to
maintain predictable order). In some situations, say when used with IList, a
natural order can be established, but in other cases when you are
considering a tree or a hashtable or an enumerator that generates its
results there may not be a natural order and ordering *may* be
unpredictable. In which case it wouldn't be possible to achieve the original
point of the feature propsal.

Another is that, unless you happen to know the length of the enumerator,
this syntax doesn't help you in the least with determining when the last
item occurs. Again, in data structures its probable that you'll get a count,
but its certainly not definate.

Yet another, somewhat related to the above, is that foreach (x in
enumerator[1]) isn't particularly sensible but it would have to be done
unless you wanted to directly access the enumerator. Also when you consider
index 0 may not be the first value returned by the IEnumerator you can't
even rely on an indexer in all cases(assuming one even exists).
The suggestion I like, meaning a way to more precisely define which items
to
execute code for. Syntax and semantics are another thing.
This suggestion is interesting, but it simply isn't the same as the original
proposal. This particular syntax allows you to specify a range to exectue
over while the original proposed a way to execute code based entirely on the
order in the enumeration, not the list or whatever the values are being read
from. The syntax proposed could operate with what you proposed pretty simply

foreach (char x in str[1,4])
{
case first: Console.WriteLi ne("First: " + x); //matches the first value,
in this case str[1]
case last: Console.WriteLi ne("Last: " + x); //matchs the last value, in
this case str[4]
case other: Console.WriteLi ne("Middle: " + x); //matches all cases other
than str[4] and str[5]

}

Of course, new syntax needs to exist. The indexer accessor would be
conflicting with actual indexers(Imagin e an indexer that returns an
IEumerable).
Can't this be done already I wonder...

In theory you could do it with a custom IEnumerable\IEn umerator pair that
wraps an existing IEnumerator, but there is no syntax I nkow of.
Nov 16 '05 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

32
578
by: James Curran | last post by:
I'd like to make the following proposal for a new feature for the C# language. I have no connection with the C# team at Microsoft. I'm posting it here to gather input to refine it, in an "open Source" manner, and in an attempt to build a ground-swell of support to convince the folks at Microsoft to add it. Proposal: "first:" "last:" sections in a "foreach" block The problem: The foreach statement allows iterating over all the...
0
8603
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9157
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9023
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8893
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
7721
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6518
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5860
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
3045
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2327
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.