C# iterators and suspend/resume in Simula 67

  • Thread starter Thread starter Jiri Kripac
  • Start date Start date
J

Jiri Kripac

Languages such as Simula 67 contain a general concept of coroutines that
allow the execution of a method to be suspended without rolling back the
stack and then later resumed at the same place as it has been suspended.

The C# iterators seem to be a special case of this general suspend/resume
concept. The "yield" statement suspends the execution of the current method
and calling MoveNext() resumes it.

I think it would be cleaner to introduce the general suspend/resume concept
to C# and then implement C# iterators on top of this general foundation. The
way C# iterators have been added to C# seems to be somewhat ad hoc; it is a
very specific and distinct functionality that does not naturally blend with
the rest of the language.

Jiri
 
Not sure I follow that. C# has a yield statement?
I think if you want to schedule your own methods, you might look into
Fibers.
 
Jiri Kripac said:
Languages such as Simula 67 contain a general concept of coroutines that
allow the execution of a method to be suspended without rolling back the
stack and then later resumed at the same place as it has been suspended.

The C# iterators seem to be a special case of this general suspend/resume
concept. The "yield" statement suspends the execution of the current
method
and calling MoveNext() resumes it.

I think it would be cleaner to introduce the general suspend/resume
concept
to C# and then implement C# iterators on top of this general foundation.
The
way C# iterators have been added to C# seems to be somewhat ad hoc; it is
a
very specific and distinct functionality that does not naturally blend
with
the rest of the language.

I've had the same opinion since I first read about iterators, however my
main problem is finding a real use outside of iteration where coroutines
would be of value and still be a clean solution. Is there a reason for
it(and derived from that a reason for the added complexity) outside of
iterating across a series of values that can't be solved in a cleaner manner
using class state instead of method state?
 
I've had the same opinion since I first read about iterators, however my
main problem is finding a real use outside of iteration where coroutines
would be of value and still be a clean solution. Is there a reason for
it(and derived from that a reason for the added complexity) outside of
iterating across a series of values that can't be solved in a cleaner manner
using class state instead of method state?

I agree about the complexity being a big issue, especially since it looks
like C# will basically convert your iterator method into a class that keeps
track of the state.

However, it might be handy for A.I. bots in a real-time game. If there were
several bots, it wouldn't be wise to run each in its own thread. Fibers are
a good solution, but since .NET doesn't support them natively, those are out
in my book (the one implentation of Fibers on .NET that I have seen is very
hackish).

In this situation it would be nice to have co-routines. Rather than having
to write lots of state-management code, you can think about the bots actions
at a higher level. Basically, if this happens, do this. But each bot would
get its share of the controlling thread's time, without the overhead of
multithreading.

Back to my first point. The added complexity isn't really needed, as
coroutines could be simulated with C# 2.0 iterators. The controlling
routine would just have to keep a list of IEnumerator objects and call
MoveNext, using some sort of Scheduling algorithm. Depending on the
situation, the iterators could return several different types of
information, from a simple dummy value indicating that more processing is
needed, to a time estimate to how much work is left remaining, or even a
priority that changes dynamically. In a game, one might return some kind of
Action object representing what the controlling routine should be doing for
that entity, which it will perform automatically until the action is
complete, at which point it will call MoveNext again to get the next action
from the entity. Then the entity coroutine (implemented as an iterator)
might look something like this.

while(this.IsAlive) {
Entity[] enemies = World.GetVisibleEnemies(this.Location);
if(enemies.Length > 0) {
yield new AttackAction(enemies[0]);
}
else if(health < 10) {
Entity healthPickup = World.FindNearestHealthPickup(this.Location);
yield new MoveToAction(healthPickup.Location);
}
else {
yield new WanderAimlesslyAction();
}
}
return;

(The yield new syntax could be made a bit cleaner with static methods...even
cleaner if C# supported executing the yield statement outside the iterator
method itself---which if I understand correctly it won't.)

The scheduling routine's code might look yucky (as IEnumerators don't really
help indicate that coroutines are being used), but this could probably be
abstracted a bit. Still, I'm a bit worried about code bloat, if the C#
compiler does in fact turn the iterator into a class that manages the state.

Of course, I'm just speculating here. I have no idea if this will actually
work. I hear that Python is good for things like this, so maybe I'll give
it a try there until I can get my hands on C# 2.0.

Anyway, there are other areas where coroutines would be helpful (mostly
simulations, hence why they're useful in games), and I'm surprised that IL
doesn't support them at some level---even if C# didn't have support for
them---since it would make it easier for certain languages to target the
runtime.

Perhaps Jiri is right, a managed fiber/coroutine API is what is needed, with
iterators implemented on top of that API. While I'm grateful that C# is
getting iterators, I still kind of feel like it's just a compiler hack. I
might feel a lot better about it with real support for coroutines in IL.

Does anyone have any links to discussions on how C# iterators are actually
implemented?

--Matthew W. Jackson
 
Matthew W. Jackson said:
I agree about the complexity being a big issue, especially since it looks
like C# will basically convert your iterator method into a class that
keeps
track of the state.

However, it might be handy for A.I. bots in a real-time game. If there
were
several bots, it wouldn't be wise to run each in its own thread. Fibers
are
a good solution, but since .NET doesn't support them natively, those are
out
in my book (the one implentation of Fibers on .NET that I have seen is
very
hackish).

In this situation it would be nice to have co-routines. Rather than
having
to write lots of state-management code, you can think about the bots
actions
at a higher level. Basically, if this happens, do this. But each bot
would
get its share of the controlling thread's time, without the overhead of
multithreading.

I see the point here, oddly this is basically iteration that you don't want
to look like interation. It may be a sufficent reason however. It would be
nice to have plain, non-iterator styled coroutines, something that doesn't
require an extra class or anything, without requiring an enumerator.
Back to my first point. The added complexity isn't really needed, as
coroutines could be simulated with C# 2.0 iterators. The controlling
routine would just have to keep a list of IEnumerator objects and call
MoveNext, using some sort of Scheduling algorithm. Depending on the
situation, the iterators could return several different types of
information, from a simple dummy value indicating that more processing is
needed, to a time estimate to how much work is left remaining, or even a
priority that changes dynamically. In a game, one might return some kind
of
Action object representing what the controlling routine should be doing
for
that entity, which it will perform automatically until the action is
complete, at which point it will call MoveNext again to get the next
action
from the entity. Then the entity coroutine (implemented as an iterator)
might look something like this.

while(this.IsAlive) {
Entity[] enemies = World.GetVisibleEnemies(this.Location);
if(enemies.Length > 0) {
yield new AttackAction(enemies[0]);
}
else if(health < 10) {
Entity healthPickup = World.FindNearestHealthPickup(this.Location);
yield new MoveToAction(healthPickup.Location);
}
else {
yield new WanderAimlesslyAction();
}
}
return;

(The yield new syntax could be made a bit cleaner with static
methods...even
cleaner if C# supported executing the yield statement outside the iterator
method itself---which if I understand correctly it won't.)

What do you mean here? I am not entirely familiar with coroutines and don't
think I've run across this concept.
The scheduling routine's code might look yucky (as IEnumerators don't
really
help indicate that coroutines are being used), but this could probably be
abstracted a bit. Still, I'm a bit worried about code bloat, if the C#
compiler does in fact turn the iterator into a class that manages the
state.

Of course, I'm just speculating here. I have no idea if this will
actually
work. I hear that Python is good for things like this, so maybe I'll give
it a try there until I can get my hands on C# 2.0.

Anyway, there are other areas where coroutines would be helpful (mostly
simulations, hence why they're useful in games), and I'm surprised that IL
doesn't support them at some level---even if C# didn't have support for
them---since it would make it easier for certain languages to target the
runtime.

Perhaps Jiri is right, a managed fiber/coroutine API is what is needed,
with
iterators implemented on top of that API. While I'm grateful that C# is
getting iterators, I still kind of feel like it's just a compiler hack. I
might feel a lot better about it with real support for coroutines in IL.

Does anyone have any links to discussions on how C# iterators are actually
implemented?

Using a quick scan across the mono code for iterators, it certaily appears
to create a nested class that handles iteration, so a sort of
psuedo-coroutines.

A pure coroutine api would be nice, a fiber API is probably best left
out(There is no guarentee that a managed Thread is actually a thread, it
could be implemented as a fiber or a user thread(similar to fibers) in a
given runtime. I'm not sure, realistically, what IL can do as far as
coroutines go, but the Mono generation uses standard return and the
contained class for state. This method should work(its how anonymous methods
work as well, the only thing I am really worried about is how would security
work in full coroutines, if the stack isn't maintained. The prolog for a
routine would have to maintain security, complicating the language a bit(It
wouldn't be particularly safe, IMHO, to change the security of a method
already executing in part between calls, thats asking for obscure bugs).
 
(The yield new syntax could be made a bit cleaner with static
What do you mean here? I am not entirely familiar with coroutines and don't
think I've run across this concept.

(btw, ooops--Forgot the updated iterator syntax in my examples...not that it
matters much).

Oh, I was just saying that rather than doing a bunch of "yield return new
MoveToCommand(pos);" it could be made to read better with a static method
that returns a command, such as "yield return MoveTo(pos);", and if the
yield could be fired in another method, then you could just simply to
"MoveTo(pos);"--saving two keywords and improving readability a bit
(although you will get no indication that execution will yield--so maybe
it's not such a good idea).

But the yield statement (as I understand) has to be in the iterator method,
in order to make the job of the compiler MUCH easier--since these do seem to
be compiled IEnumerable classes and not true fibers or coroutines.

This also means that, given a binary tree class, one can not use a recursive
method to traverse the tree. The following
won't be legal:

public IEnumerable InOrder {
get {
if(root != null) Iterate(root);
yield break;
}
}

public void Iterate(Node node) {
if(node.Left != null) Iterate(left);
yield return node.Value;
if(node.Right != null) Iterate(right);
}

If this were legal, then iterating even the most complicated of data
structures would be easy. However, since the "yield" cannot occur outside
of your iterator method, it won't be as simple as that.

Mind you, it will be easier to write with iterators in this case than it was
with a separate Enumerator class, but not too much easier...You still need
to use your own Stack to do the iteration efficiently. The only difference
is the Stack is now a local variable and not a instance variable.

I can't really think of a way to easily allow the iterator to be recursive
without being build on top of fibers or coroutines. Maybe I'm missing
something here. Maybe the compiler could determine which routines
containing yield statemetns were called by an iterator and somehow figure
out how to build the pseudo-call-stack for you. It would also mean that any
routine containing a yield could not be called by a non-iterator method. In
the end, it seems like it'd be more complicated than it is worth (especially
when you take security into account).
Using a quick scan across the mono code for iterators, it certaily appears
to create a nested class that handles iteration, so a sort of
psuedo-coroutines.

I had forgot that Mono already has these features in it (at least
partially).

I guess I should play around with my Mono install some more and see if my
idea for using iterators to simulate true coroutines in a simulation will
work well.
A pure coroutine api would be nice, a fiber API is probably best left
out(There is no guarentee that a managed Thread is actually a thread, it
could be implemented as a fiber or a user thread(similar to fibers) in a
given runtime.

I forgot about that, too, but it makes sense, with Unix being fiber-based
and not thread-based
I'm not sure, realistically, what IL can do as far as
coroutines go, but the Mono generation uses standard return and the
contained class for state. This method should work(its how anonymous methods
work as well, the only thing I am really worried about is how would security
work in full coroutines, if the stack isn't maintained.

Yeap, I forgot this too. I tend to forget about code security when I think
about features that IL should have implemented. Still, aren't there some
languages that can't be fully supported in IL because of it's lack of
coroutines? Or would all of those compilers have to do pseudo-coroutines as
well? Then what about the previously mentioned problem of calling other
methods from the coroutine?

Or do .NET versions of these languages have to be restricted in what they
support? Or maybe the compiler could make use of an unmanaged fiber API.
But this brings up security issues again.

I guess this is similar to the problem of getting SmallTalk to run on IL. I
guess some language features have to be left out.
The prolog for a routine would have to maintain security, complicating
the language a bit(It wouldn't be particularly safe, IMHO, to change the
security of a method already executing in part between calls, thats asking
for obscure bugs).

Right you are. I need to think about the problem some more.

But for now I'm happy with the (proposed) implementation of iterators. It
certainly makes it easier to provide multiple enumerators for a data type
(such as reverse enumerators, enumerators that only travel through a subset
of the items, etc.).

Back to my example:
After thinking about it, perhaps a better way to implement the problem in my
example is as follows: (The bot-manager class would be in charge of
checking the Action property after each MoveNext call.)

class Bot : Entity {

private IAction action;
private int health;
// etc.

public IAction Action {
get { return action; }
}

private void Attack(Entity entity) {
action = new AttackAction(entity);
}

private void MoveTo(Point location) {
action = new MoveToAction(location);
}

private void WanderAimlessly() {
action = new WanderAimlesslyAction();
}

// bool return value is a dummy, I suppose (I need to think about
whether a value is really needed)
// I don't suppose IEnumerable<Void> is possible .. ???
public IEnumerable<bool> Update {
get {
while(alive) {
if(health < 10) {
Entity healthPickup =
World.FindNearestHealthPickup(this.Location);
MoveTo(healthPickup.Location);
yield return true;
}
else {
Entity[] enemies =
World.GetVisibleEnemies(this.Location);
if(enemies.Length > 0) {
Attack(enemies[0]);
yield return true; // odd syntax, but it does the
job I guess
}
else {
WanderAimlessly();
yield return true;
}
}
}
yield break;
}
}

}

This is still pretty clean, and abstracts away a lot of the state
management. It's a good example one of my favorite situations in
programming---lots of messy ground work in order to make the higher-level
code cleaner. I still wish the "yield return true" statement could be
better....like I said, if non-iterator private-methods could yield, then
that statement could go in MoveTo(), Attack(), and WanderAimlessly();

Maybe I just miss the pre-multitasking days of programming in DOS where you
never had to worry about programming finite-state-machines all the time.
*sigh*. These "problems" are even worse in games, and although threads can
help, they often open a whole new can of worms.

Now time to go play with Mono a bit... Maybe I can improve my
implementation further. I'm curious to what the generated IEnumerable
class's source will look like if I put really complicated logic into the
iterator method.


--Matthew W. Jackson
 
Matthew W. Jackson said:
(btw, ooops--Forgot the updated iterator syntax in my examples...not that
it
matters much).

Oh, I was just saying that rather than doing a bunch of "yield return new
MoveToCommand(pos);" it could be made to read better with a static method
that returns a command, such as "yield return MoveTo(pos);", and if the
yield could be fired in another method, then you could just simply to
"MoveTo(pos);"--saving two keywords and improving readability a bit
(although you will get no indication that execution will yield--so maybe
it's not such a good idea).

But the yield statement (as I understand) has to be in the iterator
method,
in order to make the job of the compiler MUCH easier--since these do seem
to
be compiled IEnumerable classes and not true fibers or coroutines.

This also means that, given a binary tree class, one can not use a
recursive
method to traverse the tree. The following
won't be legal:

public IEnumerable InOrder {
get {
if(root != null) Iterate(root);
yield break;
}
}

public void Iterate(Node node) {
if(node.Left != null) Iterate(left);
yield return node.Value;
if(node.Right != null) Iterate(right);
}

If this were legal, then iterating even the most complicated of data
structures would be easy. However, since the "yield" cannot occur outside
of your iterator method, it won't be as simple as that.

Mind you, it will be easier to write with iterators in this case than it
was
with a separate Enumerator class, but not too much easier...You still need
to use your own Stack to do the iteration efficiently. The only
difference
is the Stack is now a local variable and not a instance variable.

I can't really think of a way to easily allow the iterator to be recursive
without being build on top of fibers or coroutines. Maybe I'm missing
something here. Maybe the compiler could determine which routines
containing yield statemetns were called by an iterator and somehow figure
out how to build the pseudo-call-stack for you. It would also mean that
any
routine containing a yield could not be called by a non-iterator method.
In
the end, it seems like it'd be more complicated than it is worth
(especially
when you take security into account).

Actually, from what I can tell, yield *defines* the iterator method, making
it entirely impossible to use it outside of the method you want as an
iterator.
Also, another issue I have is that the analysis of the flow to determine
where yields could occur is simply rather complex, if you consider virtuals
and other such things, it would be really tricky. A method may be to create
something like a iterator property or definition, more or less literally
designing a class but with the compiler still generating the state machine
and simply filling in pieces(enter, exit, etc), or even simply grouping
associated methods into one scope, using a defined entry point. The downside
of hte latter approach is you couldn't have reusable code(unless
complexities of iterator inheritance came into the picture...and I really
don't think the feature is worth the complexity of inheritance.)
I had forgot that Mono already has these features in it (at least
partially).

I guess I should play around with my Mono install some more and see if my
idea for using iterators to simulate true coroutines in a simulation will
work well.


I forgot about that, too, but it makes sense, with Unix being fiber-based
and not thread-based

Not to mention hosts, etc. I was reading in Chris Brumme's blog[1] today
that the hosting system in whidbey should allow the option of using fibers,
for things like SQL server and other high performance hosts.
Yeap, I forgot this too. I tend to forget about code security when I
think
about features that IL should have implemented. Still, aren't there some
languages that can't be fully supported in IL because of it's lack of
coroutines? Or would all of those compilers have to do pseudo-coroutines
as
well? Then what about the previously mentioned problem of calling other
methods from the coroutine?

Or do .NET versions of these languages have to be restricted in what they
support? Or maybe the compiler could make use of an unmanaged fiber API.
But this brings up security issues again.

I guess this is similar to the problem of getting SmallTalk to run on IL.
I
guess some language features have to be left out.

Yes, there are features that won't make it, functional languages are
especially hard hit by this(There is some research in the area, MS research
had a project porting...ML I think to the framework, including some extra IL
instructions, maybe that will make it into the system some day). On its
surface(best I can tell anyway) IL was really designed for imperative,
semi-OO languages, things like MI and a few other bits are left out,
restricting even C++. When targetting alot of languages its very hard to
abstract and still allow them all to run. Hopefully solutions will come,
with or without IL enhancements.
The prolog for a routine would have to maintain security, complicating
the language a bit(It wouldn't be particularly safe, IMHO, to change the
security of a method already executing in part between calls, thats
asking
for obscure bugs).

Right you are. I need to think about the problem some more.

But for now I'm happy with the (proposed) implementation of iterators. It
certainly makes it easier to provide multiple enumerators for a data type
(such as reverse enumerators, enumerators that only travel through a
subset
of the items, etc.).

Agreed
Back to my example:
After thinking about it, perhaps a better way to implement the problem in
my
example is as follows: (The bot-manager class would be in charge of
checking the Action property after each MoveNext call.)

class Bot : Entity {

private IAction action;
private int health;
// etc.

public IAction Action {
get { return action; }
}

private void Attack(Entity entity) {
action = new AttackAction(entity);
}

private void MoveTo(Point location) {
action = new MoveToAction(location);
}

private void WanderAimlessly() {
action = new WanderAimlesslyAction();
}

// bool return value is a dummy, I suppose (I need to think about
whether a value is really needed)
// I don't suppose IEnumerable<Void> is possible .. ???
public IEnumerable<bool> Update {
get {
while(alive) {
if(health < 10) {
Entity healthPickup =
World.FindNearestHealthPickup(this.Location);
MoveTo(healthPickup.Location);
yield return true;
}
else {
Entity[] enemies =
World.GetVisibleEnemies(this.Location);
if(enemies.Length > 0) {
Attack(enemies[0]);
yield return true; // odd syntax, but it does the
job I guess
}
else {
WanderAimlessly();
yield return true;
}
}
}
yield break;
}
}

}

This is still pretty clean, and abstracts away a lot of the state
management. It's a good example one of my favorite situations in
programming---lots of messy ground work in order to make the higher-level
code cleaner. I still wish the "yield return true" statement could be
better....like I said, if non-iterator private-methods could yield, then
that statement could go in MoveTo(), Attack(), and WanderAimlessly();

Maybe I just miss the pre-multitasking days of programming in DOS where
you
never had to worry about programming finite-state-machines all the time.
*sigh*. These "problems" are even worse in games, and although threads
can
help, they often open a whole new can of worms.

Now time to go play with Mono a bit... Maybe I can improve my
implementation further. I'm curious to what the generated IEnumerable
class's source will look like if I put really complicated logic into the
iterator method.

Hopefully iterators will supply a solution, it may not be as apparent but I
agree it is far better than writing state machines(I hate state machines,
especially wrt xml), and there are some interesting points. I wonder if it
would be possible with some sneaky thread level tricks to pop and store the
stack, in a manner similar to fibers but restoring it in the
compiler...probably not but it may be a solution as well.

Another option would be to add a requirement for CLR hosts that wish to
support coroutines need to provide a way to create a user-controlable
thread, be it a fiber or unix style user threads its irrelevent.

And yet another option would be to research how user threads work and
implement a small user-thread\fiber like library within the framework itself
to handle the code. I don't know if its possible but it is a curiosity.
 
oops, forgot the link to the blog I referenced:
http://blogs.msdn.com/cbrumme/archive/2004/02/21/77595.aspx
Daniel O'Connell said:
Matthew W. Jackson said:
(btw, ooops--Forgot the updated iterator syntax in my examples...not that
it
matters much).

Oh, I was just saying that rather than doing a bunch of "yield return new
MoveToCommand(pos);" it could be made to read better with a static method
that returns a command, such as "yield return MoveTo(pos);", and if the
yield could be fired in another method, then you could just simply to
"MoveTo(pos);"--saving two keywords and improving readability a bit
(although you will get no indication that execution will yield--so maybe
it's not such a good idea).

But the yield statement (as I understand) has to be in the iterator
method,
in order to make the job of the compiler MUCH easier--since these do seem
to
be compiled IEnumerable classes and not true fibers or coroutines.

This also means that, given a binary tree class, one can not use a
recursive
method to traverse the tree. The following
won't be legal:

public IEnumerable InOrder {
get {
if(root != null) Iterate(root);
yield break;
}
}

public void Iterate(Node node) {
if(node.Left != null) Iterate(left);
yield return node.Value;
if(node.Right != null) Iterate(right);
}

If this were legal, then iterating even the most complicated of data
structures would be easy. However, since the "yield" cannot occur
outside
of your iterator method, it won't be as simple as that.

Mind you, it will be easier to write with iterators in this case than it
was
with a separate Enumerator class, but not too much easier...You still
need
to use your own Stack to do the iteration efficiently. The only
difference
is the Stack is now a local variable and not a instance variable.

I can't really think of a way to easily allow the iterator to be
recursive
without being build on top of fibers or coroutines. Maybe I'm missing
something here. Maybe the compiler could determine which routines
containing yield statemetns were called by an iterator and somehow figure
out how to build the pseudo-call-stack for you. It would also mean that
any
routine containing a yield could not be called by a non-iterator method.
In
the end, it seems like it'd be more complicated than it is worth
(especially
when you take security into account).

Actually, from what I can tell, yield *defines* the iterator method,
making it entirely impossible to use it outside of the method you want as
an iterator.
Also, another issue I have is that the analysis of the flow to determine
where yields could occur is simply rather complex, if you consider
virtuals and other such things, it would be really tricky. A method may be
to create something like a iterator property or definition, more or less
literally designing a class but with the compiler still generating the
state machine and simply filling in pieces(enter, exit, etc), or even
simply grouping associated methods into one scope, using a defined entry
point. The downside of hte latter approach is you couldn't have reusable
code(unless complexities of iterator inheritance came into the
picture...and I really don't think the feature is worth the complexity of
inheritance.)
I had forgot that Mono already has these features in it (at least
partially).

I guess I should play around with my Mono install some more and see if my
idea for using iterators to simulate true coroutines in a simulation will
work well.


I forgot about that, too, but it makes sense, with Unix being fiber-based
and not thread-based

Not to mention hosts, etc. I was reading in Chris Brumme's blog[1] today
that the hosting system in whidbey should allow the option of using
fibers, for things like SQL server and other high performance hosts.
Yeap, I forgot this too. I tend to forget about code security when I
think
about features that IL should have implemented. Still, aren't there some
languages that can't be fully supported in IL because of it's lack of
coroutines? Or would all of those compilers have to do pseudo-coroutines
as
well? Then what about the previously mentioned problem of calling other
methods from the coroutine?

Or do .NET versions of these languages have to be restricted in what they
support? Or maybe the compiler could make use of an unmanaged fiber API.
But this brings up security issues again.

I guess this is similar to the problem of getting SmallTalk to run on IL.
I
guess some language features have to be left out.

Yes, there are features that won't make it, functional languages are
especially hard hit by this(There is some research in the area, MS
research had a project porting...ML I think to the framework, including
some extra IL instructions, maybe that will make it into the system some
day). On its surface(best I can tell anyway) IL was really designed for
imperative, semi-OO languages, things like MI and a few other bits are
left out, restricting even C++. When targetting alot of languages its very
hard to abstract and still allow them all to run. Hopefully solutions will
come, with or without IL enhancements.
The prolog for a routine would have to maintain security, complicating
the language a bit(It wouldn't be particularly safe, IMHO, to change the
security of a method already executing in part between calls, thats
asking
for obscure bugs).

Right you are. I need to think about the problem some more.

But for now I'm happy with the (proposed) implementation of iterators.
It
certainly makes it easier to provide multiple enumerators for a data type
(such as reverse enumerators, enumerators that only travel through a
subset
of the items, etc.).

Agreed
Back to my example:
After thinking about it, perhaps a better way to implement the problem in
my
example is as follows: (The bot-manager class would be in charge of
checking the Action property after each MoveNext call.)

class Bot : Entity {

private IAction action;
private int health;
// etc.

public IAction Action {
get { return action; }
}

private void Attack(Entity entity) {
action = new AttackAction(entity);
}

private void MoveTo(Point location) {
action = new MoveToAction(location);
}

private void WanderAimlessly() {
action = new WanderAimlesslyAction();
}

// bool return value is a dummy, I suppose (I need to think about
whether a value is really needed)
// I don't suppose IEnumerable<Void> is possible .. ???
public IEnumerable<bool> Update {
get {
while(alive) {
if(health < 10) {
Entity healthPickup =
World.FindNearestHealthPickup(this.Location);
MoveTo(healthPickup.Location);
yield return true;
}
else {
Entity[] enemies =
World.GetVisibleEnemies(this.Location);
if(enemies.Length > 0) {
Attack(enemies[0]);
yield return true; // odd syntax, but it does the
job I guess
}
else {
WanderAimlessly();
yield return true;
}
}
}
yield break;
}
}

}

This is still pretty clean, and abstracts away a lot of the state
management. It's a good example one of my favorite situations in
programming---lots of messy ground work in order to make the higher-level
code cleaner. I still wish the "yield return true" statement could be
better....like I said, if non-iterator private-methods could yield, then
that statement could go in MoveTo(), Attack(), and WanderAimlessly();

Maybe I just miss the pre-multitasking days of programming in DOS where
you
never had to worry about programming finite-state-machines all the time.
*sigh*. These "problems" are even worse in games, and although threads
can
help, they often open a whole new can of worms.

Now time to go play with Mono a bit... Maybe I can improve my
implementation further. I'm curious to what the generated IEnumerable
class's source will look like if I put really complicated logic into the
iterator method.

Hopefully iterators will supply a solution, it may not be as apparent but
I agree it is far better than writing state machines(I hate state
machines, especially wrt xml), and there are some interesting points. I
wonder if it would be possible with some sneaky thread level tricks to pop
and store the stack, in a manner similar to fibers but restoring it in the
compiler...probably not but it may be a solution as well.

Another option would be to add a requirement for CLR hosts that wish to
support coroutines need to provide a way to create a user-controlable
thread, be it a fiber or unix style user threads its irrelevent.

And yet another option would be to research how user threads work and
implement a small user-thread\fiber like library within the framework
itself to handle the code. I don't know if its possible but it is a
curiosity.
--Matthew W. Jackson
 
Hi Jiri,

Does the community's reply make sense to you?

If you still have anything unclear, please feel free to follow up, we will
help you.

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.
 
Hi Jeffrey,

Thanks for monitoring this discussion. Actually, I posted this issue because
I hoped someone from Microsoft C# team could step in and elaborate on this
subject. I really think C# iterators are an afterthought and C# deserves a
more general and more elegant solution.

I also mentioned Simula 67 to point out that these concepts have already
been designed some 37 years ago, and have been done more cleanly than it is
currently done in C#.

Jiri
 
Hi Jiri,

Thanks very much for your feedback.

Yes, I see your concern, actually, I am monitoring this issue.

For your concern, I suggest you feedback it to our product team at:
http://register.microsoft.com/mswish/suggestion.asp
or mail to: (e-mail address removed)

Then, our product team will consider your suggestion for C#.

Thanks for your understanding.

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