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

Forevery() writable iterator mechanism in C# 3

P: n/a
I searched the net to see if other developers have been looking for a
writable iterator in C#. I found much discussion and thus this post.

Currently (C# 2) you can not pass ref and out arguments to an iterator
method (one returning IEnumerable). I WOULD like to do this for
transformative operations on a collection.

I realize the need to lock target, etc.

Does anyone know how to handle 'writable iterators' in C# 2?

Is anyone aware of feature requests for C# to provide a forevery() with a
matching interface like IEnumerable?

Thanks ahead of time. I want to put in a product feature request but want to
do some research before hand.
Mar 9 '06 #1
Share this Question
Share on Google+
14 Replies


P: n/a
shawnk <Sh****@discussions.microsoft.com> wrote:
I searched the net to see if other developers have been looking for a
writable iterator in C#. I found much discussion and thus this post.

Currently (C# 2) you can not pass ref and out arguments to an iterator
method (one returning IEnumerable). I WOULD like to do this for
transformative operations on a collection.

I realize the need to lock target, etc.

Does anyone know how to handle 'writable iterators' in C# 2?

Is anyone aware of feature requests for C# to provide a forevery() with a
matching interface like IEnumerable?

Thanks ahead of time. I want to put in a product feature request but want to
do some research before hand.


I'm not entirely clear about what you want. Could you give a sample
program that you'd *like* to work?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Mar 9 '06 #2

P: n/a

"shawnk" <Sh****@discussions.microsoft.com> wrote in message
news:B5**********************************@microsof t.com...
I searched the net to see if other developers have been looking for a
writable iterator in C#. I found much discussion and thus this post.

Currently (C# 2) you can not pass ref and out arguments to an iterator
method (one returning IEnumerable). I WOULD like to do this for
transformative operations on a collection.

I realize the need to lock target, etc.

Does anyone know how to handle 'writable iterators' in C# 2?
Is anyone aware of feature requests for C# to provide a forevery() with a
matching interface like IEnumerable?

Thanks ahead of time. I want to put in a product feature request but want
to
do some research before hand.


Why would the interface need ref/out itself?
There's nothing stopping the "yield"ing function from destructively
modifying it's collection regardless of what it returns, is there? (Although
it's certainly not common or expected.)
A destructive operation will by definition be refelected in all references
to the collection, so "out" is not needed.
And if it's not destructive, you can just write a little "collect" wrapper
that'll go though the enum and return a new ICollection.

IMHO, if you are:
- making a copied list (non-destructive) or returning each element, then
use a return value
- if you are performing a destructive operation, make the fn "void" and
do not return a value - this make it clear what's going on

If all your types are reference types (class instances), then each returned
element from the enumerator is a shared, mutable, object - so you can always
change it through normal means. (This isn't C++, class instances aren't
passed by value on the stack) If you want to change the "stored" element
itself of the current iteration in the underlying collection from *outside*
of the enumertor function, that's another story -- but that's really bad
practice -- especially considering that there may be no actual underlying
collection at all - that's really a major point of "yield", to provide
referential transparency in such matters. Consider:
yield return 1;
yield return 2;
yield return 3;

Your not going to be able to "write" to this interator no matter what you
do.

One way to do this would be to expose an iterator that returned proxies for
the storage of each element, if in fact there is a backing-store for the
enumeration. For example:

// Of course, generics too...
interface IEnumStorageProxy { object Value { get; set; }};
interface IEnumHasStorage { GetStorageProxyEnum(); }

foreach ( object elem in coll)
elem.Change(blah); // changing object inside collection as usual

foreach ( IEnumStorageProxy cell in coll.GetStorageProxyEnum())
{
object oldVal = c.Value;
c.Value = new MyObject(); // replace the object in the collection
}

This requires no new language features, though the interfaces would need to
be exposed from the framework collections.

m

Mar 9 '06 #3

P: n/a

Typos...
interface IEnumHasStorage { GetStorageProxyEnum(); } Should be: interface IEnumHasStorage { IEnumeration GetStorageProxyEnum(); } object oldVal = c.Value;
c.Value = new MyObject(); // replace the object in the collection Should be: object oldVal = cell.Value;
cell.Value = new MyObject(); // replace the object in the
collection


but I'm sure you got the idea...
I'm not saying the names of the interfaces/methods are so nice either :)
Mar 9 '06 #4

P: n/a
Please forgive the slow response. I'm swamped:-)

I will use the following category to articulate different iterator types;

Iterators
Indexors [] : This[] (_idr)
Sequencer r/w iterator : ISequencer - forevery (_sqr)
Enumerator ro iterator : IEnumerable - foreach (_emr)

Example Context of use; Migrating items in two nullable collections.

100 items that move between nullable enumerable collections with
constructors A_col(100) and B_col(100).
So there are 100 'slots' for the items to 'live in'.

The identity of each item is its index - for example item '6'.
Item '6' is always in A_col[6] or B_col[6].
When not 'in residence' in A_col[] the A_col[6] = null.
Same for B_col[].

Problem assignment:

I want to be able to move any items in B_col[] to A_col[]
and then print only the items in residence in A_col[].

Sequencer solution:

forevery ( My_item_cls Itm_A_sqr
in A_col_ins,
My_item_cls Itm_B_sqr
in B_col_ins
){

if ( Itm_B_sqr.In_residence() )
{
Itm_A_sqr = Itm_B_sqr.Move_out();
}

if ( Itm_A_sqr.In_residence() )
{
Console.WriteLine(" Item[{0}] - {1}",
Itm_A_sqr.ID
Itm_A_sqr.Value
);
}
}

The 'forevery' is 'stackable' to handle multiple collections.
The 'sequencer' (_sqr) is 'writable' so I can assign in an elegant type safe
manner.

For simplicity ignore all threading and synchronization issues and
conventions.
These would be done under the covers by the collection classes.

I hope this helps.
Thank you for your response.
I will review Mike's excellent response and reply asap.
This (next) code example will show why ref and out parameters are useful in
iterator methods
(those returning IEnumerable). Please be patient with my response time.

Shawnk

PS. The smallest 'example program' is big.

"Jon Skeet [C# MVP]" wrote:
shawnk <Sh****@discussions.microsoft.com> wrote:
I searched the net to see if other developers have been looking for a
writable iterator in C#. I found much discussion and thus this post.

Currently (C# 2) you can not pass ref and out arguments to an iterator
method (one returning IEnumerable). I WOULD like to do this for
transformative operations on a collection.

I realize the need to lock target, etc.

Does anyone know how to handle 'writable iterators' in C# 2?

Is anyone aware of feature requests for C# to provide a forevery() with a
matching interface like IEnumerable?

Thanks ahead of time. I want to put in a product feature request but want to
do some research before hand.


I'm not entirely clear about what you want. Could you give a sample
program that you'd *like* to work?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Mar 10 '06 #5

P: n/a
Shawnk wrote:

<snip>
PS. The smallest 'example program' is big.


That in itself counts against the proposal, IMO. However, having seen
your sample, is this the kind of thing you mean?

using System;
using System.Collections.Generic;

class Test
{
static void Main()
{
List<int> ints = new List<int>();
// Set up the initial list
for (int i=0; i < 5; i++)
{
ints.Add(i);
}

// Square each element
forevery (int x in ints)
{
x = x*x;
}

// Print them out
foreach (int x in ints)
{
Console.WriteLine (x);
}
}
}

would result in:
0
1
4
9
16

If that's the case, I don't think there's any need to use ref/out.
Instead, the interface would need to be just like IEnumerator, but with
Current having a setter as well as a getter. Any assignment to the
variable would end up as a call to the setter.

I'm not sure it's particularly necessary, but I'm not entirely averse
to it...

Jon

Mar 10 '06 #6

P: n/a
Mike,

Imagine the same situation as in my reply to Jon Skeet with A_col[] and
B_col[].
The collection could be an int?[] array of nullable ints.

The '_itr_mth' LLP tag means 'Iterator Method'.

Problem assignment: Print out list of resident items with their identity

Code solution : Using 'out parameter' in an iterator method (one returning
Enumerable).

int l_actual_itm_idx = 0; // The actual int?[l_idx] non-null item index in
a sparse array of int?[100] items.

l_temp_itm_col_ins = m_source_itm_col_ins.
Actual_items_with_index_itr_mth( l_actual_itm_idx );

foreach( int l_int_emr in m_actual_item_int_based_gnc_col_ins )
{
System.Console.WriteLine("Item #{0} = {1}", l_actual_itm_idx,
l_int_emr );
}

If you work it out (and I didn't screw it up :-0) the output skips over
nullable 'slots' ia the terator method internals and only returns existing
items.

In addition it will set the l_actual_itm_idx (item index) to the index in
the int?[100]array which, in this contrived example, is the identity of the
item. (see response to Jon Skeet).

The temporary collection we generate (l_temp_itm_col_ins) acts as an
'iterative delegate' that can return the value of the item identity
(l_actual_itm_idx) along with the item.

Note that identity here, and this is key, is determined by the collection.

Although the 'identity' is contrived the key point is the collective
responsibility for determining datum l_actual_itm_idx. For collectively
determined pheonomea that exists 'in aggregate' the collection needs a 'data
channel' back to the iterative body (WriteLine).

Note, again key point, the item has no knowledge of its 'context state'
which is only internal to the collection and may, in fact, be dependent upon,
the sequence of iteration itself.

The traveling salesman problem and other 'path oriented solutions' can have
'weights' as sortable item properties and, therefore, expressed in a
mechanism similar to our contrived, but relevant, example.

I hope this answers your intitial question 'why would the inteface need
ref/out itself'

My next post will address transformative operations using sequencers.
Context is changeble, growing objects persisted in XML over a long period.

Key point. The data structure itself changes from one Item XML schema to
another.

This is schema composition (basically)
"Mike" wrote:

"shawnk" <Sh****@discussions.microsoft.com> wrote in message
news:B5**********************************@microsof t.com...
I searched the net to see if other developers have been looking for a
writable iterator in C#. I found much discussion and thus this post.

Currently (C# 2) you can not pass ref and out arguments to an iterator
method (one returning IEnumerable). I WOULD like to do this for
transformative operations on a collection.

I realize the need to lock target, etc.

Does anyone know how to handle 'writable iterators' in C# 2?
Is anyone aware of feature requests for C# to provide a forevery() with a
matching interface like IEnumerable?

Thanks ahead of time. I want to put in a product feature request but want
to
do some research before hand.


Why would the interface need ref/out itself?
There's nothing stopping the "yield"ing function from destructively
modifying it's collection regardless of what it returns, is there? (Although
it's certainly not common or expected.)
A destructive operation will by definition be refelected in all references
to the collection, so "out" is not needed.
And if it's not destructive, you can just write a little "collect" wrapper
that'll go though the enum and return a new ICollection.

IMHO, if you are:
- making a copied list (non-destructive) or returning each element, then
use a return value
- if you are performing a destructive operation, make the fn "void" and
do not return a value - this make it clear what's going on

If all your types are reference types (class instances), then each returned
element from the enumerator is a shared, mutable, object - so you can always
change it through normal means. (This isn't C++, class instances aren't
passed by value on the stack) If you want to change the "stored" element
itself of the current iteration in the underlying collection from *outside*
of the enumertor function, that's another story -- but that's really bad
practice -- especially considering that there may be no actual underlying
collection at all - that's really a major point of "yield", to provide
referential transparency in such matters. Consider:
yield return 1;
yield return 2;
yield return 3;

Your not going to be able to "write" to this interator no matter what you
do.

One way to do this would be to expose an iterator that returned proxies for
the storage of each element, if in fact there is a backing-store for the
enumeration. For example:

// Of course, generics too...
interface IEnumStorageProxy { object Value { get; set; }};
interface IEnumHasStorage { GetStorageProxyEnum(); }

foreach ( object elem in coll)
elem.Change(blah); // changing object inside collection as usual

foreach ( IEnumStorageProxy cell in coll.GetStorageProxyEnum())
{
object oldVal = c.Value;
c.Value = new MyObject(); // replace the object in the collection
}

This requires no new language features, though the interfaces would need to
be exposed from the framework collections.

m

Mar 10 '06 #7

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:11*********************@e56g2000cwe.googlegro ups.com...
Shawnk wrote:

<snip>
I'm not sure it's particularly necessary, but I'm not entirely averse
to it...

<more snips>
That's how I feel about it. I think its noble to make something that works
no matter what the underlying collection is (again, assuming there is one)
but there are some problems:
(1) To me it's not necessarily easier to read -- it can actually be so
"generic looking" that it's hard to tell whats actually happening. I think
destructive operations should be explicit. (Maybe if I came from an STL
background I'd feel differently.)
(2) You're kind of assuming iterators that work by maintaining a "cursor"
though a collection. C# iterators are moving toward using "yield" which
saves activation state and acts as a limited sort of co-routine, which has
many advantages; however, making Current writable is not possible in general
using this method of writing iterators. (But I guess your distinction of
Sequencer vs. Enumerator is basically a cursor.)
(3) Different collections have different interfaces -- for example, if you
had a priority queue, and you do a "move out", where does the priority (or
other baggage for a particular container class) go which needs to stay
semantically "attached" to the item before it can be added to another queue?
(4) IMHO, the basic collection type is usually an obvious choice up-front
90% of the time, so spending too much time on anything past read-only
iterators isn't worth the complexity. Plus, if you have the collection
black-boxed behind an opaque type anyway and the interface to the outside
world is stable, you can change the complex data-munging code without
disturbing your clients - better to not let them get a hold of your
collections themselves anyway - publish your own GetEnumerator() calls that
can return the interior ones, or ones you code.
(5) I think writable iterators are weird -- they appear very "functional",
but go against that paradigm as they mutate rather than copy.

But I guess if there is a solution that is natural in the c# world (whether
the "proxy" version or an out/ref version) then I could be convinced -
still, I wonder if the effort is worth the gain.

m
Jon

Mar 10 '06 #8

P: n/a
Mike,

I think your solution (an actually Jon Skeet's solution) is what I was
looking for in tems of a 'writable item' enumerator. Thanks to you both for
clarifying that issue for me (a writable sequencer vs a read only enumerator).

So (I think) we can put to rest the 'forevery()' request because the
'writable item' functionality is already there in 'foreach'.

I think, perhaps, some of my C# V 1 thinking is still in my mind :-)

I do want to clarify the issue of the ref/out with a better, really small
example, just like Jon Skeet did. I'm looking for a 'data channel' to flow
data from the iterative method back to the code block containing the
foreach() clause.

This is for 'collective phenomena' that exists above the 'item' level and
should really stay at that level of stratification (the collective level) to
partition the complexity of the problem space correctly (I hope thats not
obtuse).

In simple terms I would like to be able NOT to use the item to pass back or
process this kind of 'collective data'.

Thank you for your patience on my lack of better examples. I'll try to add a
beter example of the weekend to this post just to summarize both your
recommendations.

Thanks again.

Shawnk

"Mike" wrote:

"shawnk" <Sh****@discussions.microsoft.com> wrote in message
news:B5**********************************@microsof t.com...
I searched the net to see if other developers have been looking for a
writable iterator in C#. I found much discussion and thus this post.

Currently (C# 2) you can not pass ref and out arguments to an iterator
method (one returning IEnumerable). I WOULD like to do this for
transformative operations on a collection.

I realize the need to lock target, etc.

Does anyone know how to handle 'writable iterators' in C# 2?
Is anyone aware of feature requests for C# to provide a forevery() with a
matching interface like IEnumerable?

Thanks ahead of time. I want to put in a product feature request but want
to
do some research before hand.


Why would the interface need ref/out itself?
There's nothing stopping the "yield"ing function from destructively
modifying it's collection regardless of what it returns, is there? (Although
it's certainly not common or expected.)
A destructive operation will by definition be refelected in all references
to the collection, so "out" is not needed.
And if it's not destructive, you can just write a little "collect" wrapper
that'll go though the enum and return a new ICollection.

IMHO, if you are:
- making a copied list (non-destructive) or returning each element, then
use a return value
- if you are performing a destructive operation, make the fn "void" and
do not return a value - this make it clear what's going on

If all your types are reference types (class instances), then each returned
element from the enumerator is a shared, mutable, object - so you can always
change it through normal means. (This isn't C++, class instances aren't
passed by value on the stack) If you want to change the "stored" element
itself of the current iteration in the underlying collection from *outside*
of the enumertor function, that's another story -- but that's really bad
practice -- especially considering that there may be no actual underlying
collection at all - that's really a major point of "yield", to provide
referential transparency in such matters. Consider:
yield return 1;
yield return 2;
yield return 3;

Your not going to be able to "write" to this interator no matter what you
do.

One way to do this would be to expose an iterator that returned proxies for
the storage of each element, if in fact there is a backing-store for the
enumeration. For example:

// Of course, generics too...
interface IEnumStorageProxy { object Value { get; set; }};
interface IEnumHasStorage { GetStorageProxyEnum(); }

foreach ( object elem in coll)
elem.Change(blah); // changing object inside collection as usual

foreach ( IEnumStorageProxy cell in coll.GetStorageProxyEnum())
{
object oldVal = c.Value;
c.Value = new MyObject(); // replace the object in the collection
}

This requires no new language features, though the interfaces would need to
be exposed from the framework collections.

m

Mar 10 '06 #9

P: n/a
Mike and Jon,

Relative to the collection ontology issues of foreach()/forever() and the
read/write nature of iteration.

I did some research over the weekend. I covered the linguistics of
'iteration' in human language, the mathematical community and (of course)
programming. I ended up with about 60 PDF files of blogs, articles, and
specs.

My final focus was the evolution of the C# 'iteration' specifications in
Ander's (Inventor of C# - and his MS dev team) statements in the C# specs.

The intent of this investigation was to verify your statements on the read
only (or not) nature of the 'enumerator' in C#.

The final (and most important) reference point is Anders specifications
for C# V 2. From the C# V2 spec he writes. (Start Quoted section)

(Hejlsberg.book Page 470 Friday, October 10, 2003 7:35 PM)

The generic and nongeneric enumerable interfaces contain a single member,
a GetEnumerator method that takes no arguments and returns an enumerator
interface. An enumerable acts as an enumerator factory. Properly
implemented enumerables generate independent enumerators each time their
GetEnumerator method is called. Assuming the internal state of the
enumerable has not changed between two calls to GetEnumerator, the two
enumerators returned should produce the same set of values in the same
order. This should hold even if the lifetime of the enumerators overlap
as in the following code sample.

using System;
using System.Collections.Generic;
class Test
{
static IEnumerable<int> FromTo(int from, int to) {
while (from <= to) yield return from++;
}
static void Main() {
IEnumerable<int> e = FromTo(1, 10);
foreach (int x in e) {
foreach (int y in e) {
Console.Write("{0,3} ", x * y);
}
Console.WriteLine();
}
}
}

(End Quoted section)

Numerable articles and presentations mention the 'read only' nature of
'enumerators' to emphasize the 'repeatable results' aspect of 'iterators'
above.
I contrast the above reference point (Anders statement) with the
mathematical definition of 'Iterative Method' found at;

www.wikipedia.org

which states;

(Quoted section)

In computational mathematics, an iterative method attempts to solve a
problem (for example an equation or system of equations) by finding
successive approximations to the solution starting from an initial guess.
This approach is in contrast to direct methods, which attempt to solve the
problem in one-shot (like solving a linear system of equations Ax = b by
finding the inverse of the matrix A).

......

Probably the first iterative method appeared in a letter of Gauss to a
student of his. He proposed solving a 4-by-4 system of equations by
repeatedly solving the component in which the residual was the largest.

The theory of stationary iterative methods was solidly established with
the work of D.M. Young starting in the 1950s. The Conjugate Gradient
method was also invented in the 1950s, with independent developments by
Cornelius Lanczos, Magnus Hestenes and Eduard Stiefel, but its nature and
applicability were misunderstood at the time. Only in the 1970s was it
realized that conjugacy based methods work very well for partial
differential equations, especially the elliptic type.

(End quoted section)

The proposed C# V3 forevery() - ISequencer feature would be used in code
structures where collections are inherently writable, changable, and
iterations have changing results. Collections are seen more as 'living
places' for 'traveling items' that move about under their own volition or
under external impetus. The collections are also exist in a 'binding
matrix' that is used for navigation and migration decisions.

Thus, the 'stackable' forevery() computation features support an
indeterminate 'changing' nature of iteration results.

A set of 'dynamic conventions', such as new items (created during in
iteration pass)
go to end of list, provide for repeatablity of process (not result).

Real world examples would exist in the context of incoming data
composition of perception mechanisms for satellite telemetry, a machine
trying to understand what a person is saying and underwater robots.

In these applications data items go through stages of data processing
fostered by their location (which collection they belong to).

Writable iteration (sequencers) applies constantly changing 'aggregate
state space' phenomena to individual items in their individual journey
through the data processing system.

I am still in research mode and wish to review more material.

Later this week I will post a summary statement on
need for a authoritative collection ontology from the Microsoft folks that
can help to reduce some of the confusion (mine and others) related to
iterative terminology in C#. (I quickly checked Microsoft eBooks on
computing before any research).

I note that your combined understanding of iterators in C# is much better
than mine.

The code syntax issues of (1) ref/out [data channel], (2) terminology and
(3) foreach() vs forevery() are separate but inter-related. I will focus
the remaining posts (in this thread) to issues 2 and 3. These issues are
basically issues of semantics in the C# collection ontology.

I do have one short post on 'iterative data channels' (return, the enumerator
itself (in the foreach() statement), the ref/out). I will put that in a
separate
post.

I would like to defer to terms used in the C# C5 collection library out of
Copenhagen (IT University Technical Report Series TR-2006-76) but I need
to complete my linguistic groundwork first.

Mike, your excellent comment;

I think writable iterators are weird -- they appear very "functional", but
go against that paradigm as they mutate rather than copy.

is very true. The application context (mentioned above) has a
fundamentally different view of mutability let alone the deterministic
implications because of the constant change nature of the collection
content. Thus your use of the word 'paradigm' is exactly the sematic issue
I am trying to understand.

This is the exact impetus; semantic clarity of the C# collection ontology
and its resulting syntactic expression that I wish to understand. With
this in mind I will be reviewing both of your statements on the mutable
nature of 'enumerators' this week.

Thanks, again, for your patience with my response time.

With all due respect I want to thank you ahead of time for any continued
input. Also thank you again for you input in helping me understand the 'C#
enumerator semantics'.

Shawnk

PS. The forevery() establishes an focused complementary collective processing
paradigm to complement foreach() via a read vs write functional basis.

"Mike" wrote:

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:11*********************@e56g2000cwe.googlegro ups.com...
Shawnk wrote:

<snip>
I'm not sure it's particularly necessary, but I'm not entirely averse
to it...

<more snips>


That's how I feel about it. I think its noble to make something that works
no matter what the underlying collection is (again, assuming there is one)
but there are some problems:
(1) To me it's not necessarily easier to read -- it can actually be so
"generic looking" that it's hard to tell whats actually happening. I think
destructive operations should be explicit. (Maybe if I came from an STL
background I'd feel differently.)
(2) You're kind of assuming iterators that work by maintaining a "cursor"
though a collection. C# iterators are moving toward using "yield" which
saves activation state and acts as a limited sort of co-routine, which has
many advantages; however, making Current writable is not possible in general
using this method of writing iterators. (But I guess your distinction of
Sequencer vs. Enumerator is basically a cursor.)
(3) Different collections have different interfaces -- for example, if you
had a priority queue, and you do a "move out", where does the priority (or
other baggage for a particular container class) go which needs to stay
semantically "attached" to the item before it can be added to another queue?
(4) IMHO, the basic collection type is usually an obvious choice up-front
90% of the time, so spending too much time on anything past read-only
iterators isn't worth the complexity. Plus, if you have the collection
black-boxed behind an opaque type anyway and the interface to the outside
world is stable, you can change the complex data-munging code without
disturbing your clients - better to not let them get a hold of your
collections themselves anyway - publish your own GetEnumerator() calls that
can return the interior ones, or ones you code.
(5) I think writable iterators are weird -- they appear very "functional",
but go against that paradigm as they mutate rather than copy.

But I guess if there is a solution that is natural in the c# world (whether
the "proxy" version or an out/ref version) then I could be convinced -
still, I wonder if the effort is worth the gain.

m
Jon


Mar 13 '06 #10

P: n/a

Mike - Jon,

This is a summary statement on the forevery() concept of write capable
iterators.

Contrary to my earlier statement I decided to fold the ref/out parameter
issue of iterator methods back into the 'forevery()' feature request.

I've decided to post a feature request for the C# compiler for a forevery
statement that provides a 'parameterized' data channel via ref/out
parameters. This data channel can then be used by the iterator to
'channel' data back in addition to the return statement.

The 'ease of use'/'use case'/'utility' is the ability to add a method to
an already existing collection infrastructure.

By adding a 'quick method' you do not need to 'typecast' a new class for
an item collection infrastructure.

This compliments the 'generic' approach for generating 'item class' data
channels (via yield return). It does not replace them or seek to mimic
that functionality.

Relative to the 'write only' behavior of an enumerator I came up with a
brief iterator classification system based on various (and nefarious :-)
sources on the web. Three major characteristics that determine iterator
behaviour are;

1. Read only iterators - (enumerators) No item or collection content change.

2. Writeable iterators - (Sequencers) An item state space is changed (via
the sequencer).

3. Transform iterator - (Transformer) Collection contents is changed via the
transform iterator.

A quick (from the hip) labeling of these major behaviour characteristics is;

1. Enumerators
2. Sequencers
3. Transformers

This is contrived however because comparators and other kinds of iterators
have very characteristic
and well known behavioral patterns. A better iterator classification scheme
would be fall under
the three broad categories of;

1. Enumeration
2. Sequencing
3. Transformation

Thus a 'collection ontology' would contain an 'iteration domain' which would
include
an 'iterator classification' (this from various blogs, papers, etc).

The iterator classification
is loosely partitioned using the 'scope of change' that the iterator exhibits.

The 'iterator classification' is partitioned, in a general sense, into these
three areas.

1. Enumeration - no state space change to item or collection (state space
change is local to iterator)
2. Sequencing - Item state space can change
3. Transformation - Collection state space can change (item list or
collection metadata - statistics, etc)

So in summary the iterator's characteristic behavior, in terms of state
space change, provides one (not the only) way to categorize iterators.
( That is, does the iterator effect any state space change at all and if so
how 'broad' is the scope of what it can change.)

An enumerator and comparator are examples of Enumeration (in this
classification system)
because neither effect any state space change to the item or the collection.

Thanks to your response I can see that C# enumerators allow mutable items
and would be classified as
'sequencers' in this (truncated) collection ontology. From what I can tell
from other sources
the following is true.

//#----

Iteration A single repeatable step in the iterative process.
The result is not necessarily repeatable but the
functionality is.

Operator A part of or component of an iterator 'type'.
A iterator may be composed of a single 'iteration
operator' or,
it may be composed of several 'iteration operators'
depending upon
it function and the type of iterator (as described below).

Enumerator A type of object that can provide several methods of
enumerating a collection.
class

//#----

In looking over various blogs, papers ect a better
more practical and pragmatic iterator classification is given below.

//#----

Iterators Characteristic Behaviour

Indexer [] - iterates via numeric 'index' over a collection
Enumerator Pointer function - ro iterator - References an item in
collection
Comparator Iterates over a collection and compares a 'reference' item
with a target item
Filter Filters the 'view' of a collection
Blocker Blocks incoming items from residing in the collection
Sequencer Pointer function - r/w iterator - Can change the value of
the item it iterates over
Generator yields a 'virtual collection' which may be infinite
Modifier Changes one or more items that it iterates across
Transformer Effects the item set in the collection. Does not effect
the item state space.
(a) slicer - Cuts off a section of a collection an (1)
moves it or (2) destroys it.
(b) router - Rerouts incoming items who desire to
reside in the 'this' (immediate) collection to another collection
Translator Provides a mapping of items in a target collection to
(a) another item in another collection or
(b) a transformed item or
(c) a value resulting from the target item of an
iterative cycle
(c) a value resulting from a set of target items in two
or more collections
Combinator Provides a result (item or value) based on
(a) one or more items in a collection
(b) one or more items in two or more collections
Recursor A iterator that calls itself - such as a 'tree iterator'
that whose 'drilling' is done recursively.

//#----

To wrap up, the 'forevery()' function would partition iterators into read
only vs.
read/write logical domains. Once formally partitioned the forevery() allows
'state space change scope'
to determine the iteration code generated (as in generic iterators) for
'item change' and
'collection change' behaviors.

Techniques for 'write modality' in the foreach() loop or in the iterator
statements
are published and discussed but I would prefer a solid and simple forevery()
statement
to formally imply the expanded scope of state change (for sequencers, etc).
A corresponding
ISequencer (or any other label) interface that allows ref/out would open a
data channel
at the 'collection state space' level to the caller code block.

Thank you both (Mike and Jon) for your input regarding enumerators in C# and
the
scope of the state space effects of iterators using IEnumerable and
IEnumerator.

Shawnk

PS I did not mention the control flow, anonymous method, and lexical closure
perspective
to classify iterators as control flow was orthogonal to my focus on the
scope of state space change
of the iterator.

PPS. Microsoft's forums usually 'rewrite' some of my spacing so I hope
you'll forgive any
layout problems in the pragmatic iterator classification scheme above.

Mar 14 '06 #11

P: n/a
One thing I forgot to mention. In the 'pragmatic classification' each
iterator type would have a corresponding interface. For example.

1. Sequencer - ISequencer
2. Comparator - IComparator
3. Enumerator - IEnumerator
4. Slicer - ISlicer

etc.

In this way the foreach() and forevery() statements would allow a set of
interfaces to be compatible with their operation (during the iteration
process).

Also the matched set of (1) loop statement (foreach,forevery) and (2)
interface (Iwhatever) allows for a 'matched set' of implied behaviour that
allows.

1. Simplicity of syntax (use behavioral conventions in generic code
generation)
2. Articualtion of well known functional behaviours

The combination of iterator classification (the core behavioral semantics),
the loop statement and the collection interface would help to reduce
confusion regarding the overall data flow in system level data
compostion/decomposition patterns (like the pipeline pattern, staged
observers, etc.).
Mar 14 '06 #12

P: n/a
This is exactly what I was looking for.

"Jon Skeet [C# MVP]" wrote:
Shawnk wrote:

<snip>
PS. The smallest 'example program' is big.


That in itself counts against the proposal, IMO. However, having seen
your sample, is this the kind of thing you mean?

using System;
using System.Collections.Generic;

class Test
{
static void Main()
{
List<int> ints = new List<int>();
// Set up the initial list
for (int i=0; i < 5; i++)
{
ints.Add(i);
}

// Square each element
forevery (int x in ints)
{
x = x*x;
}

// Print them out
foreach (int x in ints)
{
Console.WriteLine (x);
}
}
}

would result in:
0
1
4
9
16

If that's the case, I don't think there's any need to use ref/out.
Instead, the interface would need to be just like IEnumerator, but with
Current having a setter as well as a getter. Any assignment to the
variable would end up as a call to the setter.

I'm not sure it's particularly necessary, but I'm not entirely averse
to it...

Jon

Mar 15 '06 #13

P: n/a
"shawnk" <Sh****@discussions.microsoft.com> a écrit dans le message de news:
B5**********************************@microsoft.com...

|I searched the net to see if other developers have been looking for a
| writable iterator in C#. I found much discussion and thus this post.
|
| Currently (C# 2) you can not pass ref and out arguments to an iterator
| method (one returning IEnumerable). I WOULD like to do this for
| transformative operations on a collection.
|
| I realize the need to lock target, etc.
|
| Does anyone know how to handle 'writable iterators' in C# 2?

Were you aware that List<T> provides a ForEach(Action<T>) method ?

Does this help ?

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Mar 15 '06 #14

P: n/a

"Joanna Carter [TeamB]" wrote:
Were you aware that List<T> provides a ForEach(Action<T>) method ?

Does this help ?


Joanna,

Thank you for the input. The List<T> .. Action<T> is a mutability
mechanism and is similar in its state space change scope to iterator
methods. Both are great and very useful to me.

I am still researching some iterative functionality beyond this.

Delegates passed into the iterator (from the iterators point of view)
allow incoming functionality (incoming to the item/collection state space)
but;

1. In the caller block state space the iterator itself is still not
assignable.

2. A parameterized 'outgoing' data channel (from the item/collection state
space) is not provided.

As Jon Skeets (excellent) code showed, the foreach() iterator is not
assignable but it is mutable (public fields of the target object are
assignable). The forevery() would allow for assignment. I would also
like the forevery() to allow for an additional 'ad hoc' (quick and dirty -
easy to do) outgoing parameterized data channel.

Thus client (caller code block with forevery()) code could change
collection content (assignment) and server (iterator code (both incoming
via delegate and native via collection iterator methods) code could
provide more bandwidth for outgoing data (via the ref/out parameters of
forevery() incoming delegates and native iterator methods).

The key thing I am interested in is (1) iterator assignability and (2)
outgoing data channels via a parameterized path (in addition to the
already existing method return data channel (which is 'outgoing' from
item/collection perspective)).

I'll be making two other posts soon. (1) To discuss the categorical
classification of iterators and (2) a post to discuss iteration data
channels in the context of stratification levels (L1 - Iterator state
space, L2 -Item, L3 - Collection, etc).

Some types of iteration data channels (not all types) are 'level bound'
and provide channels for 'iterator to iterator' data flow, 'item to item'
data flow, 'collection to collection' data flow, 'container to container'
data flow'. (I'm ignoring cross level data flow).

Using the ref/out parameterized data channel of forevery() would allow
(IMHO) a better articulation of stratification levels of the system state
space (iterator, item, collection, container, etc). The levels of
abstraction (L1 -> LN) are thus less abstract because they map to the
functional roles of pattern participants. This is for collection
iteration data flow patterns where participants are inherently stratified.

To my limited knowledge, the patterns and practices group has not provided
a complete, closed and correct computing collection ontology. Without a
peer reviewed, community contributed iteration classification scheme (a
part of the ontology) it is a bit more of a challenge to show
'architectural holes' in the current design of C# enumerators.

The current C# enumerator is such an excellent set of work (I really like
it) that I want to be very sure of its current limitations. These
limitations are good, in themselves, and qualify a consistent set of
behaviors, such as throwing exceptions on collection content change
detected by enumerators. In this world the collection content is
'preferred stable' for nominal operations.

Any iterator classification (language independent) could be bisected along
a 'preferred stable' and 'preferred dynamic' concept line. Non-preffered
behavior is signaled by exception (the 'check_revision() found in real
world enumerators). You can create 'enumerators' that 'prefer' a dynamic
world but then you loose the 'salt' provided by that very characteristic
you accepted.

On the other hand you can't make a language inherent loop statement syntax
(forevery(), formyfavorite(), fortheoneIlikedyesterday()) for each
category of iterator. Thus the request (in this post) to verify the 'basic
paradigm shift' of a 'preferred dynamic content' for the collection (as Mike
informally verified).

The forevery() concept is, as Mike noted, a significant change in the
iterator paradigm. Collection content revision numbers, for example, are
not logically inherent in a collection that is expected to be constantly
changing. A more dynamic set of behavioral characteristics are needed to
provide a consistent framework for all iterator patterns using a
forevery() approach (in a 'preffered dynamic world').

I want to thank you again for your input. I like 'incoming delegates' in
both iterator methods and language syntax artifacts (Like Action<T>).

Since the delegate signatures do not allow parameterized ref/out they
prevent some of things I would like to express with outgoing data channels
(in a iteration process context).

I hope I have articulated the (1) scope of state space change and (2)
outgoing data channel issues clearly. There are only about (maybe) a
dozen kinds of iterator (indexors, viewers, enumerators, comparators,
sequencers, ..) as far as I can see (using a state space change scope
qualifier for categorization).

The forevery() combined with a ref/out would provide the single needed
language artifact to (I think - still researching this) create all
twelve types of iterator in C# (as categorized above).

In addition the forevery() is like a warning sign that says 'Dorthy and
Toto have just left Kansas' (Wizard of Oz, The Matrix) and things (both
items AND collections) are 'dynamic' instead of 'stable'.

I hope to post the other posts sometime this month. Thanks again for your
input.

Shawnk

PS. I am ignoring control flow issues and any other functionality that
may be used to categorize iterator types.
Mar 17 '06 #15

This discussion thread is closed

Replies have been disabled for this discussion.