473,508 Members | 4,712 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

C# Language Specification - Enumeration

Sure... IEnumerable was inconvenient suggesting a separate class to service
the enumeration, IEnumerator, and multiple operations: Current, MoveNext,
Reset. (I'll warp the definition of "operation" for a second if you don't
mind).

However, it existed within intuitive language semantics, whereas the new
"yield" keyword, while highly convenient, is also one of the most gross
warping of language concepts to date...

public IEnumerator GetEnumerator() {
foreach(foobar o in _co) yield return o;
}

So, it essentially redefines the concepts of how functions are supposed to
behave, as well as how return values interact with return types. It also
introduces the new keyword with a very specialized purpose.

One way to explain "yield", is to say that it boxes your object into an
IEnumerator, saves the execution state of your function, and also restores
the execution state the next time your function is called, even before the
keyword is invoked during regular instruction flow, so it establishes the
loop's next startup state. Therefore, it redefines the laws of instruction
sequencing, and is sort of a quantum keyword that exists in multiple spots at
once during the existance of that function.

It would make sense to have IEnumerate be an allowed combination of
IEnumerable and IEnumerator, and to add a GetNext function that can return
the proper generic variable type. Then make "yield" its own return-style
keyword:

(** Proposed Syntax:
public class Woo : IEnumerate
{
...
public object GetNext() {
if(_collection==null) return null;
foreach(object obj in _collection) {
yield obj;
}
}
...
}
**)

This would still allow the full existing enumeration capability, but would
introduce this new style in a cleaner and more intuitive way.
Nov 17 '05 #1
4 5644
Marshal,

The problem with condensing the two interfaces into one is that you end
up losing the fact that a type can say "I can have my contained items
iterated through, and this is the mechanism by which you do it". That's
different from your interface, which says "I can have my contained items
iterated through, and ^I^ will do it". The IEnumerable/IEnumerator
functions are better, IMO, because it will allow for better encapsulation of
code, at the least.

The other problem with your proposal is that you can't tell if there are
any more items in your iteration. Yeah, you could check against return
value of GetNext for null, but if you are enumerating value types, then you
can't do this, since they can't be null (unless you use Nullable types, but
that wasn't around in 1.0, and you would have to do this ugly case logic to
determine if it was a value type or not, and then if it was null).

Using your method would end up looking something like this:

// An object, to check for null.
object o = null;

// The type of the object.
T t;

// Loop. You have to check for null here since your implementation would
return
// null if there are no items in the enumeration. The assumption here
// is that at the end of the loop, you would return null.
while ((o = collection.GetNext()) != null)
{
// Cast to the original object.
t = (T) o;

// Do some stuff.
}

This is a little more messy than what you have to do now. First, you
need to have the object instance just to check null, and you have a nasty
assignment and comparison in the while statement. Compare that to how
foreach is expanded by the compiler using the current IEnumeration interface
(and assuming that collection implements IEnumeration):

// The type t.
T t;

while (!collection.MoveNext())
{
// Get the value.
t = collection.Current;
}

You have t, and you know if you hit the end, but without that ugliness
in between (the o variable checking for null).

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Marshal" <Ma*****@discussions.microsoft.com> wrote in message
news:17**********************************@microsof t.com...
Sure... IEnumerable was inconvenient suggesting a separate class to
service
the enumeration, IEnumerator, and multiple operations: Current, MoveNext,
Reset. (I'll warp the definition of "operation" for a second if you don't
mind).

However, it existed within intuitive language semantics, whereas the new
"yield" keyword, while highly convenient, is also one of the most gross
warping of language concepts to date...

public IEnumerator GetEnumerator() {
foreach(foobar o in _co) yield return o;
}

So, it essentially redefines the concepts of how functions are supposed to
behave, as well as how return values interact with return types. It also
introduces the new keyword with a very specialized purpose.

One way to explain "yield", is to say that it boxes your object into an
IEnumerator, saves the execution state of your function, and also restores
the execution state the next time your function is called, even before the
keyword is invoked during regular instruction flow, so it establishes the
loop's next startup state. Therefore, it redefines the laws of instruction
sequencing, and is sort of a quantum keyword that exists in multiple spots
at
once during the existance of that function.

It would make sense to have IEnumerate be an allowed combination of
IEnumerable and IEnumerator, and to add a GetNext function that can return
the proper generic variable type. Then make "yield" its own return-style
keyword:

(** Proposed Syntax:
public class Woo : IEnumerate
{
...
public object GetNext() {
if(_collection==null) return null;
foreach(object obj in _collection) {
yield obj;
}
}
...
}
**)

This would still allow the full existing enumeration capability, but would
introduce this new style in a cleaner and more intuitive way.

Nov 17 '05 #2
> The problem with condensing the two interfaces into one is that you end
up losing the fact that a type can say "I can have my contained items
iterated through, and this is the mechanism by which you do it". That's
different from your interface, which says "I can have my contained items
iterated through, and ^I^ will do it". The IEnumerable/IEnumerator
functions are better, IMO, because it will allow for better encapsulation of
code, at the least.
My proposal should be equivilent with the current proposals on using
"yield", it just cleans up the syntax. In both cases, you can still use
IEnumerable and IEnumerator for the reasons you point out, and both proposals
on "yield" are used for the ^I^ will do it case anyway.
The other problem with your proposal is that you can't tell if there are
any more items in your iteration...
Again, it's basically a cleaner way of expressing the existing yield syntax,
which has no problem terminating the enumeration in magic code. I was imaging
it being used in a foreach statement.

If the GetNext function is called directly as in your example, then I would
expect it should throw an exception if the caller tries to read beyond the
end of the array. They should write something like:

(** Proposed Syntax:
collection.Reset();
while(collection.HasValues) { o = collection.GetNext(); ... }
**)

However, they should be as unlikely to do that, as they would be to call
GetEnumerator directly in the current model which uses yield. If they did so
in the current model, it would not appear as intuitive.
Using your method would end up looking something like this:

// An object, to check for null.
object o = null;

// The type of the object.
T t;

// Loop. You have to check for null here since your implementation would
return
// null if there are no items in the enumeration. The assumption here
// is that at the end of the loop, you would return null.
while ((o = collection.GetNext()) != null)
{
// Cast to the original object.
t = (T) o;

// Do some stuff.
}

This is a little more messy than what you have to do now. First, you
need to have the object instance just to check null, and you have a nasty
assignment and comparison in the while statement. Compare that to how
foreach is expanded by the compiler using the current IEnumeration interface
(and assuming that collection implements IEnumeration):

// The type t.
T t;

while (!collection.MoveNext())
{
// Get the value.
t = collection.Current;
}

You have t, and you know if you hit the end, but without that ugliness
in between (the o variable checking for null).

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com


Nov 17 '05 #3
See inline:
The other problem with your proposal is that you can't tell if there
are
any more items in your iteration...
Again, it's basically a cleaner way of expressing the existing yield
syntax,
which has no problem terminating the enumeration in magic code. I was
imaging
it being used in a foreach statement.


Ok, so it's cleaner, but at what cost? Clean doesn't mean anything if
actually implementing it is not.
If the GetNext function is called directly as in your example, then I
would
expect it should throw an exception if the caller tries to read beyond the
end of the array. They should write something like:

(** Proposed Syntax:
collection.Reset();
while(collection.HasValues) { o = collection.GetNext(); ... }
**)
There is a specific reason why the designers of .NET didn't use
something like HasValues and GetNext. The reason for that is that a good
number of people actually forget to code the call to move to the next item
in the enumeration, leading to infinite loops. With the way it is now (with
the all to MoveNext returning whether or not there are elements), you don't
have that problem.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

However, they should be as unlikely to do that, as they would be to call
GetEnumerator directly in the current model which uses yield. If they did
so
in the current model, it would not appear as intuitive.
Using your method would end up looking something like this:

// An object, to check for null.
object o = null;

// The type of the object.
T t;

// Loop. You have to check for null here since your implementation would
return
// null if there are no items in the enumeration. The assumption here
// is that at the end of the loop, you would return null.
while ((o = collection.GetNext()) != null)
{
// Cast to the original object.
t = (T) o;

// Do some stuff.
}

This is a little more messy than what you have to do now. First, you
need to have the object instance just to check null, and you have a nasty
assignment and comparison in the while statement. Compare that to how
foreach is expanded by the compiler using the current IEnumeration
interface
(and assuming that collection implements IEnumeration):

// The type t.
T t;

while (!collection.MoveNext())
{
// Get the value.
t = collection.Current;
}

You have t, and you know if you hit the end, but without that
ugliness
in between (the o variable checking for null).

--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

Nov 17 '05 #4


Marshal wrote:
Sure... IEnumerable was inconvenient suggesting a separate class to service
the enumeration, IEnumerator, and multiple operations: Current, MoveNext,
Reset. (I'll warp the definition of "operation" for a second if you don't
mind).
IEnumerable expresses that enumeration is supported, "I am iterable, you
can obtain that enumeration by invoking GetEnumerator()".

IEnumerator expresses a "pointer" into an enumeration, "This is how far
you are along the enumeration".

IEnumerator have Current/MoveNext(), JAVA Iterator have hasNext() and
next(), C++ iterators have "++" and "*". Actually I don't recall seeing
any protocol for iteration that don't have seperate
advance/advance-check and value obtain, and thus multiple operations.

I would say that whether Reset() should be included in IEnumerator is
open to discussion.
So, it essentially redefines the concepts of how functions are supposed to
behave, as well as how return values interact with return types. It also
introduces the new keyword with a very specialized purpose.
It lets you define a generator for IEnumerator using function-syntax.
Other languages have this too, python and it is essential in ruby.

Whether this "redefines the concepts of how functions work" or not...
well, you are really just defining a function that returns an
enumerator. There is no "quantum magic" here, only compiler assisted
closure greneration.

Notice that the caller of the function doesn't care if actual "quantum
magic" was used to implement the IEnumerator returned. The implementer u
could do it by implementing the closure, MoveNext() and Current by hand
in a class that stores the relevant state and implement IEnumerator.

Function-syntax is rather nice for describing enumeration, and
syntactic-sugar support for storing the used local-variables in a
helper-class and implementing Current/MoveNext() is convinient to me in
that syntax.
One way to explain "yield", is to say that it boxes your object into an
IEnumerator, saves the execution state of your function, and also restores
the execution state the next time your function is called, even before the
keyword is invoked during regular instruction flow, so it establishes the
loop's next startup state. Therefore, it redefines the laws of instruction
sequencing, and is sort of a quantum keyword that exists in multiple spots at
once during the existance of that function.
Another way to explain it would be that it generates an IEnumerators
MoveNext() and Current functions from the closure available in the
function. This is a known technique known from functional programming: a
higher-order function.
It would make sense to have IEnumerate be an allowed combination of
IEnumerable and IEnumerator, and to add a GetNext function that can return
the proper generic variable type. Then make "yield" its own return-style
keyword:
I don't see the benefit of combining IEnumerable and IEnumerator, see above.

The problems in combining the two concepts is manifest in our
example-code. Where is _collection coming from (the interface-usage
prevents you from having a protocol of accepting it at construction time).
(** Proposed Syntax:
public class Woo : IEnumerate
{
...
public object GetNext() {
if(_collection==null) return null;
foreach(object obj in _collection) {
yield obj;
}
}
...
}
**)

I don't really understand how this is substantially different from or
better than:

public static IEnumerator Enumerate(ICollection c) {
foreach ( object o in c )
yield return o;
}

Which fits into the current enumeration-idiom in C#.

The choice of "yield return" vs. just "yield" is open to discussion, but
i suspect "yield return" was chosen because no program containing that
sequence of tokens would be valid in previous C# revisions.
This would still allow the full existing enumeration capability, but would
introduce this new style in a cleaner and more intuitive way.


Perhaps you are finding the IEnumerable/IEnumerator design
non-intuitive, and perhaps transfer that onto the "yield return" construct?

I find that the IEnumerable/IEnumerator design is spot-on and I haven't
really seen any languages which doesn't make that distinction in one
form or another.

Perhaps you need just a little more assimilation before you accept the
design ;) (notice smiley.... i'm not being hostile here)

--
Helge Jensen
mailto:he**********@slog.dk
sip:he**********@slog.dk
-=> Sebastian cover-music: http://ungdomshus.nu <=-
Nov 17 '05 #5

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

Similar topics

1
1517
by: Andrew James | last post by:
Gentlemen, I'm currently in the process of designing a language which will be used to specify sets of files on a WebDAV server, encoded in a URL. The aims of the language are to (in no particular...
1
12616
by: Justin Wright | last post by:
I know that I can set up an enumeration as follows ( just typed in quick so may have syntax errors ): <xsd:simpleType name="colors"> <xsd:restriction base="xsd:string"> <xsd:enumeration...
63
5789
by: Tristan Miller | last post by:
Greetings. Do any popular browsers correctly support <q>, at least for Western languages? I've noticed that Mozilla uses the standard English double-quote character, ", regardless of the lang...
86
3842
by: Randy Yates | last post by:
In Harbison and Steele's text (fourth edition, p.111) it is stated, The C language does not specify the range of integers that the integral types will represent, except ot say that type int may...
6
2324
by: Tony Whitter | last post by:
Does anyone know how much changed between the final draft dated October 2002 and the Ecma-334 C# Language Specification 2nd edition dated December 2002 and if there is a change history document...
42
2134
by: Eric Gunnerson [MS] | last post by:
You may download the new specification at the C# Developer Center (http://msdn.microsoft.com/vcsharp/language). There is a discussion forum for the C# language on that same page. If you don't...
0
1142
by: Marshal [DirectX MVP 2003] | last post by:
In anticipation of the chat, I have filtered all of my current enhancement aleration ideas through the software development community, via the following postings: C# Language Specification -...
3
1690
by: albert.neu | last post by:
Hello! What is the difference between "library parts" of C99 and "language parts" of C99. see...
2
1699
by: Vneha | last post by:
Q:- What is the difference between Sun Java tutorials and Java Language specification? Q:- What if i start studying Java Language Specification and leave the tutorials because i have seen that...
0
7228
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7393
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...
1
7058
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...
0
7502
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5635
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,...
1
5057
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...
0
4715
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...
1
769
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
426
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

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.