Iterators & generators (RE: Real Problems with Python)
Harald Hanche-Olsen
hanche at math.ntnu.no
Tue Feb 15 13:53:29 EST 2000
+ Andrew Cooke <andrew at andrewcooke.free-online.co.uk>:
| That finally hammered home to me just what continuations are all about.
| Does anyone have something similarly elegant that shows a coroutine?
Not me, but let me show you what I learned about it, way back in '73.
I had the pleasure of learning assembly language programming at the
feet of a master -- Ole Johan Dahl of Simula fame -- and of course he
just had to teach us about coroutines and how to do them. It was
amazingly simple and powerful.
I need to tell you a bit about the CDC3300 and the assembly language
used for it (Compass): There were no such modern amenities as a
stack. The usual way to code a subroutine was as follows:
FOO JMP *
...
JMP,I FOO
and you would call FOO with this instruction:
JSR FOO
JSR stood for "Jump, Save Return" and that is what it did: It computed
the return address (PC+1) and saved it in the address field at address
FOO (indicated by the asterisk above), then jumped to FOO+1. To
return, FOO just jumps to its own start address, which by now contains
a jump instruction correctly addressed to get back (except we usually
made the jump indirect, as shown, to save a machine instruction).
If you understand this, we're ready for the coroutine example. All it
takes is three lines of glue, then the coruotines themselves:
FOOBAR JMP FOO
BARFOO JMP BAR
JMP,I FOOBAR
FOO ... (skipping the usual JMP * glue)
...
JSR FOOBAR (call BAR)
...
JSR FOOBAR (call BAR again)
...
BAR ... (skipping the usual JMP * glue)
...
JSR BARFOO (call FOO)
...
JSR BARFOO (call FOO again)
...
To get the whole thing going, just execute, e.g.,
JMP FOO
Whenever FOO wants to invoke BAR, it does so via a JSR to the glue at
FOOBAR. The return address is stored where the address FOO used to
be, and the glue code jumps to BAR. Then BAR does some work, calls
BARFOO, which stores a new return address in the glue where BAR's
address used to be, then jumps to FOOBAR, which jumps to FOO - no,
there is a new address there now, so it jumps *into* FOO, not to the
top. And so control is transferred back and forth, and both FOO and
BAR can be written as if *it* is the main program and it's just
calling on its coroutine as if it were a mere subroutine. Mighty
handy if, as it was in the example task we were given, FOO would need
to consume a stream of data, massage it in some way, and BAR would do
further work on the resulting stream of output data from FOO.
(My code as shown assumes that the pair will go on forever, or until
one of them halts the program. To allow a controlled return, a
trivial amount of extra JMP * / JSR - type glue code will be needed.)
What a delight to be able to post ancient assembly code on c.l.py...
Geriatrically y'rs,
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- "There arises from a bad and unapt formation of words
a wonderful obstruction to the mind." - Francis Bacon
More information about the Python-list
mailing list