Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

co-routines (iterators with yield in some languages)

2 views
Skip to first unread message

Marcio

unread,
Jun 24, 2003, 12:33:52 PM6/24/03
to

It's nice to see that this old concept is making a comeback in some
languages: http://gary.burd.info/content/news/7.html ,
http://www.gotdotnet.com/team/csharp/learn/Future/VCS%20Language%
20Changes.doc

In Python:
http://www.python.org/doc/current/ref/yield.html
When a yield statement is executed, the state of the generator is frozen
and the value of expression_list is returned to next()'s caller. By
``frozen'' we mean that all local state is retained, including the current
bindings of local variables, the instruction pointer, and the internal
evaluation stack: enough information is saved so that the next time next()
is invoked, the function can proceed exactly as if the yield statement were
just another external call.


I would really like to see this kind of support in Eiffel one day. See
http://smartzilla.loria.fr/show_bug.cgi?id=279

marcio

Doug Hockin

unread,
Jun 25, 2003, 12:16:39 AM6/25/03
to
Generators are a basic part of the Icon language, which
has been around for a long time.

http://www.cs.arizona.edu/icon/docs/ipd266.htm

There's a lot of neat things in Icon.

-- Doug

Doug Pardee

unread,
Jun 25, 2003, 12:29:36 PM6/25/03
to
Marcio <mqmne...@sglebs.com> wrote:
> It's nice to see that this old concept is making a comeback in some
> languages: http://gary.burd.info/content/news/7.html ,
> http://www.gotdotnet.com/team/csharp/learn/Future/VCS%20Language%
> 20Changes.doc
> [snip]

> I would really like to see this kind of support in Eiffel one day. See
> http://smartzilla.loria.fr/show_bug.cgi?id=279

Yuck. Why don't we add pointers and goto while we're at it?

Co-routines completely violate the basics of structured programming.
Exiting a method in the middle of a nest of control structures is
acceptable to some people, but to enter a method in the middle of that
nest is merely disgusting.

Furthermore, co-routines are a procedural device that do not fit well
with Object Orientation, at least as the term is typically used in the
Eiffel community. Co-routines especially do not fit well with
Command/Query Separation, Disciplined Exceptions, and Design by
Contract(tm).

We went around on this a couple of years ago. See
http://groups.google.com/groups?threadm=b0f57d2d.01100...@posting.google.com
for that discussion.

Marcio

unread,
Jun 26, 2003, 12:31:02 PM6/26/03
to
dougp...@yahoo.com (Doug Pardee) wrote in
news:fa7f90f3.03062...@posting.google.com:

> Yuck. Why don't we add pointers and goto while we're at it?


Eiffel already has POINTER, no ?

And eposix adds support for pointers, have you seen that ? I actually
use it to manipulate buffers in memory, which I use to pass to sockets,
zlib etc. Very useful.

Regarding gotos, I have not faced a need to use them, the other
language mechanisms have been enough for me so far.


> Co-routines completely violate the basics of structured programming.

Smalltalk had/has the notion of Process (originally no time-slicer,
and always shared memory) that could be created, and you could yield from
any method. Does that violate the basics of structured programming in
your opinion ?


> Exiting a method in the middle of a nest of control structures is
> acceptable to some people, but to enter a method in the middle of that
> nest is merely disgusting.


How about Threads or concurrent objects that synchronize in some
check points in the middle of a method, is that disgusting ? What if you
use coroutines instead of Threads (basically no time slicer for your
coroutines), is that disgusting ?

I think there's a distiction between the iterator using coroutines
and just pure basic coroutines.


> Furthermore, co-routines are a procedural device that do not fit well
> with Object Orientation, at least as the term is typically used in the
> Eiffel community. Co-routines especially do not fit well with
> Command/Query Separation, Disciplined Exceptions, and Design by
> Contract(tm).


I have noticed that even concurrent programming has a hard time with
command-query because of the large synchronization window you have:


buffer.read_line
buffer.last_line


You can't synchronize at the method level anymore because now you
have to call 2 methods. Other languages have it easy by having read_line
do the read&return of the value (violating command/query) and
synchronizing at the method call level. It would be nice to have the
benefit of both.

Maybe when "separate" in Eiffel arrives for real we'll be able to do
decent concurrent programming in Eiffel, but I think in this regard the
language design/implementation is about 10 years late.

And what if my platform does not have Threads ? Will "separate" work
? Using what ? Green Threads ? Throw the time slicer away - isn't that
just co-routines underneath ?


> We went around on this a couple of years ago. See

> http://groups.google.com/groups?threadm=b0f57d2d.0110070549.30de4281@po
> sting.google.com for that discussion.


Very interesting. I see a mix of people wanting to do different
things but using simple examples.

If I wanted to apply an operation to a collection, I'd use an agent
in Eiffel, or a block in Smalltalk: aCollection do: [:element | element
doSomething]. No need for coroutines etc.

Now let's assume I had conceptually independent tasks. Now, if I had
a machine with quite a bit of memory and a compiler that supported
Threads or "separate", I'd use Threads or "separate" objects.

Now, if I want to write a program with a small footprint, on a
platform where I can't or don't want to use Threads, then I find myself
in a tough spot. Usually I have to code all sorts of state machines
because I am trying to remember state across "events" without using the
execution stack.

With the use of coroutines you can have small, efficient programs
while retaining the high-level abstractions of your programming language
and existing libs. I see them as being orthogonal. These things cooperate
and when one would block the other can assume the execution control.


Maybe the answer for Eiffel is to have "separate" work even in
platforms that do not have Threads (embedded etc). I should be able to
say that I want a compact implementation and have the compiler generate
code based on coroutines underneath, no Threads. I doubt compiler
implementors will do that, but that would be cool.

Here's a different scenario. Most IO-based libs are implemented
assuming they will traverse the input bytes in their own loops. Take a
compiler for example. Let's say I am using a compiler generated using
GOBO. Now let's say I am receiving TCP/IP connections from clients (say I
have my own server), and I want to use a parser to parse the request,
which can be many megabytes long. If I do not / cannot use Threads, I
will use select and have event-based programming with sockets ("here's a
few more bytes"). Can I call the parser and say "here's more bytes for
you, please compile them and remember your state until the next time I
call you again with a few more bytes" ? No, I can't (just imagine reusing
a descendent recursive parser in this context). Do I want to rewrite
GOBO's compiler-compiler package to allow this kind of event-based
behavior ? No I do not. However, if I used coroutines I could use my
GOBO-generated compiler to compile bytes from a socket as I receive them.
The compiler would be blocked trying to read bytes that are not there,
and execution would be transferred to my other co-routine (probably
another one handling another TCP/IP client connecting to my server).
Therefore the coroutines make the traditional kind of programming ("I own
the loop traversing the input") compatible with event-based (where
resources are limited, and you want a compact implementation).


So, that's the general mechanism I want. Existing code can still rely
on the execution stack for state, but execution of this code can be
interleaved with others, based on "lack of data" / "presence of data", so
that small efficient programs can be written. Gosh, even normal GCs can
be used because there's no need to "stop all threads so you can GC" or
any of that.

Maybe you can show how this kind of real problem can be solved with a
compiler like SmartEiffel today ? I mean, you are writing an event-based
server (like Xitami, etc) and not using Threads, and still want to use a
GOBO-generated compiler to compile your request bytes, which you obtain
in chunks, 8KB at a time.

Of course there are many other scenarios which are similar. I just
tried to use one that most people can understand, and can try to tackle
with existing libs. You can use yaesockets and try to write a server that
accepts multiple concurrent connections from clients, using SmartEiffel,
for example. Try to solve the problem above and then let me know how you
did it. I'd be interested to know.

Thanks,

marcio


Berend de Boer

unread,
Jun 26, 2003, 3:40:27 PM6/26/03
to
>>>>> "Marcio" == Marcio <mqmne...@sglebs.com> writes:

>> Yuck. Why don't we add pointers and goto while we're at it?

Marcio> Eiffel already has POINTER, no ?

goto's are coming :-)


Marcio> And eposix adds support for pointers, have you seen
Marcio> that ? I actually use it to manipulate buffers in memory,
Marcio> which I use to pass to sockets, zlib etc. Very useful.

An understatement :-)


Marcio> Maybe when "separate" in Eiffel arrives for real
Marcio> we'll be able to do decent concurrent programming in
Marcio> Eiffel, but I think in this regard the language
Marcio> design/implementation is about 10 years late.

What you mean is *safe* concurrent programming. You can use threads,
with all the issues. It's unfortunate you can't do COM+ with Eiffel,
else you would have a fairly safe concurrent base as well.

On Unix forking has always been available. Forking is an absolutely
brilliant way for concurrent programming. Way easier than threads. And
that has been available to Eiffel programmers all the time.

The issues are mainly on Windows. Unfortunately, that's an important
slice of the market.


Marcio> And what if my platform does not have Threads ? Will
Marcio> "separate" work ? Using what ? Green Threads ? Throw the
Marcio> time slicer away - isn't that just co-routines underneath
Marcio> ?

Yep, but it's about additional safety that the language guarantees. An
OS without threads is rare these days.

--
Regards,

Berend.
** you're welcome to the #eiffel irc channel on irc.freenode.net

Marcio

unread,
Jun 27, 2003, 12:14:30 AM6/27/03
to
Berend de Boer <ber...@xsol.com> wrote in news:uhe6c1...@xsol.com:

> What you mean is *safe* concurrent programming. You can use threads,
> with all the issues.


No I can't. My Eiffel compiler is SmartEiffel.


> Marcio> And what if my platform does not have Threads ? Will
> Marcio> "separate" work ? Using what ? Green Threads ? Throw the
> Marcio> time slicer away - isn't that just co-routines underneath
> Marcio> ?
>
> Yep, but it's about additional safety that the language guarantees. An
> OS without threads is rare these days.


I believe that if I write my server with co-routines and you write yours
with Threads, I can probably beat you in performance and memory consumption.
Unfortunately we can't compare, as my EIffel compiler does not support
Threads out-of-the-box, and neither does it support co-routines.

If "separate" could gen code that did not rely on Threads, but just co-
routines, that would be great. Say a compiler option.

marcio

Marcio

unread,
Jun 27, 2003, 1:33:12 PM6/27/03
to
Berend de Boer <ber...@xsol.com> wrote in news:uhe6c1...@xsol.com:

> On Unix forking has always been available. Forking is an absolutely


> brilliant way for concurrent programming. Way easier than threads. And
> that has been available to Eiffel programmers all the time.


I don't think that a server like Apache forks for every new TCP/IP
client that connects.

And I don't think it creates a new Thread for every socket that
connects.


http://www.javaworld.com/jw-03-1999/jw-03-volanomark.html "While making
threads thriftier in their resource usage leads to impressive gains in
connection scaling, the thread-per-socket model simply cannot scale up to
tens or hundreds of thousands of concurrent connections. Some form of
multiplexing many connections to a single thread is required. Native
applications traditionally use the select() or poll() system calls to
achieve this. Java does not yet have a select() facility in its sockets
API, but it is clear that one is needed as server-side Java applications
grow in magnitude and scope."


See similar comments at http://www.volano.com/report/index.html
(Conclusions) and also take a look at http://www.cs.wustl.edu/
~jxh/research/research.html


marcio

Pascal Obry

unread,
Jun 27, 2003, 1:59:55 PM6/27/03
to

Berend de Boer <ber...@xsol.com> writes:

> On Unix forking has always been available. Forking is an absolutely
> brilliant way for concurrent programming. Way easier than threads. And
> that has been available to Eiffel programmers all the time.

Maybe easier and brilliant but quite resources consuming. A thread is a lot
lighter than a fork/exec...

Pascal.

--

--|------------------------------------------------------
--| Pascal Obry Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--| http://perso.wanadoo.fr/pascal.obry
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595

Berend de Boer

unread,
Jun 29, 2003, 5:03:41 PM6/29/03
to
>>>>> "Marcio" == Marcio <mqmne...@sglebs.com> writes:

>> On Unix forking has always been available. Forking is an
>> absolutely brilliant way for concurrent programming. Way easier
>> than threads. And that has been available to Eiffel programmers
>> all the time.


Marcio> I don't think that a server like Apache forks for
Marcio> every new TCP/IP client that connects.

The 1.x version does. It uses preforking to have processes ready for
new users. Forking is really fast on Unix.

Berend de Boer

unread,
Jun 29, 2003, 5:05:49 PM6/29/03
to
>>>>> "Pascal" == Pascal Obry <p.o...@wanadoo.fr> writes:

>> On Unix forking has always been available. Forking is an
>> absolutely brilliant way for concurrent programming. Way easier
>> than threads. And that has been available to Eiffel programmers
>> all the time.

Pascal> Maybe easier and brilliant but quite resources
Pascal> consuming. A thread is a lot lighter than a fork/exec...

We're not talking about exec here, just forking. And what resources
are you talking about? Modern Unixes have copy-on-write, the overhead
is almost neglectable. The applications that might warrant threads are
1 in a thousand or so.

Marcio

unread,
Jun 29, 2003, 7:16:23 PM6/29/03
to
Berend de Boer <ber...@xsol.com> wrote in news:uel1cz...@xsol.com:

> Marcio> I don't think that a server like Apache forks for
> Marcio> every new TCP/IP client that connects.
>
> The 1.x version does.


I was thinking 2.x, sorry, I should have made that clear in my
original message.

marcio

Pascal Obry

unread,
Jun 30, 2003, 2:04:27 PM6/30/03
to

Berend de Boer <ber...@xsol.com> writes:

> We're not talking about exec here, just forking.

Ok, so I withdraw my comment about the resource consuming feature :)

0 new messages