
BBS, Lua, Coroutines, Mongrel2: Part 1 - alexkay
http://sheddingbikes.com/posts/1287306747.html
======
fogus
I ran a BBS in the Baltimore area as a kid. Of course, it was only open after
midnight and closed again at 4 am. I used to set my alarm and sneak upstairs
to turn off/on the ringers on the other phones. I had about 8 regular callers
from all over MD -- this was practically international to a 9 year-old. I ran
TriBBS.

~~~
zedshaw
Yeah I love BBSes. Seems a lot of other folks like them too so I'm going to
continue hacking on this as the official "something more than chat" demo.

------
eliben
Somewhat related to the coroutine vs. FSM issue:
[http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-
al...](http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-
to-state-machines/)

[apologize for the plug, but IMHO it's very relevant]

~~~
silentbicycle
You don't need coroutines to do this - you can use tail calls, if the language
provides tail-call optimization. (Python doesn't, but Lua does.) I might post
a code sample translating your FSM example later, but I need to go run
errands.

~~~
zedshaw
That'd be super slick. BTW, you're the guy that wrote sidereal right? I'm
using it for the redis action. Very nice.

~~~
silentbicycle
Yes, and thanks. :)

Have you seen my library (<http://github.com/silentbicycle/tamale>) for doing
Erlang-style pattern matching in Lua, BTW? I still need to document it (I'm
working on briefly explaining why pattern matching matters to people who have
never used it), but in the mean time, a glance at the README and the test
suite should suffice.

------
yummyfajitas
_Enter Lua's coroutines, which are really the only full and complete
coroutines._

I'm curious, could someone explain this statement? I was under the impression
that Python had coroutines as well. Syntactically they are a bit uglier (yield
statements everywhere), but functionally similar:
<http://www.python.org/dev/peps/pep-0342/>

(Admittedly, I don't know a lot about coroutines, so I could be way off here.)

In code: <http://gist.github.com/630921>

~~~
zedshaw
There's actually a theory of what makes a complete coroutine, similar to what
makes a complete closure. I don't remember all of it off the top of my head,
but it's basically:

1\. coroutines act as pipes that can send (yield) and receive values.

2\. coroutines are first class citizens like closures so they can be passed
around as values, referenced, garbage collected, etc.

3\. they can yield from any point in the stack, so you can use them inside
functions deeply nested without any caller N frames up from knowing about it.

4\. one side of a coroutine doesn't have to know about the other side, just
like functions.

5\. you can inspect them to find out if they are running, suspended, etc.

I'm probably missing some things, but the gist is there's very few languages
that do all of this. Lua's the only one that really gets them right and makes
it easy, with probably Lisp continuations being next. I'm sure there's other
languages but I know Python, Ruby, and Java really get these wrong.

I'd also say that Erlang adds one very _very_ sexy addendum to this in that
you can take any process and send it over the wire, store it, recover it, etc.

~~~
silentbicycle
It's probably helpful to think of coroutines as first-class functions with
independent call stacks, which can be suspended and resumed (potentially
returning and passing in new arguments). Coroutines are also usable as (one-
shot) continuations, and continuations can be used to implement coroutines.

There's a great paper about coroutines ("Revisiting Coroutines",
[http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.58.4...](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.58.4017))
co-written by one of the primary Lua authors.

FWIW, you can also stream Lua functions (with string.dump), though it takes a
bit of extra trouble to stream functions with nonlocal values
("upvalues"/closures). I don't know if it's possible to stream Lua coroutines,
though. As with most things, Erlang's immutability makes streaming them much
easier.

------
jens187
I ran a BBS out of Stockholm, Sweden on my Atari 1040STFM with a MegaDrive
60MB harddrive which was really loud in my bedroom all day and all night, like
a vacum cleaner. Many different people from all over the country dialed my one
phone line connection. People downloaded mostly Public Domain applications
have music in MOD-format. I met up with some of the people logging in, they
were often older than me and could by booze, haha. Just reminiscing....

------
cageface
The problems Zed lists for a co-routine based web app (essentially tying
important state to a single server) are also problems for the Scala/Lift
framework. Dave Pollak, the author of Lift, claims that maintaining some
server-side state solves more problems than it causes but I haven't had a
chance to test this myself in a real app.

------
chriseidhof
Does anybody have a good solution for the "Sharing Coroutine State
Sucks"-problem? I've thought a very long time about this (in my case, using
continuations in FP instead of coroutines in Lua), but I still can't seem to
come up with a good answer.

I guess one way to deal with it is by mechanically transforming the co-
routines into a FSM. This is very similar to defunctionalization. However, I
don't know of a language that does this well. Any suggestions?

~~~
mprovost
With Stackless Python you can pickle (serialize) tasklets (coroutines). I
built a Seaside-style web app in Stackless where each response would get
pickled and saved to disk. When a new request with that id comes in you just
unpickle it back into a tasklet and resume where you left off. You can do this
between processes and machines. I don't see why you couldn't put them in a db
but I was just using shared disk. What you're looking for are serializable
continuations which some languages can handle.

~~~
chriseidhof
Very impressive. I'll have to look into that.

------
Rickasaurus
I ran a Renegade BBS on a machine inside my step-dad's office (Hartford CT
area). He was nice enough to let me use his fax number (as he almost never
did) with the caveat that he could disconnect people if he needed it.

Very fun times. I used to love the Barren Realms Elite leagues most of all.

------
johngalt
Sysop of a Wildcat BBS on a 286. Still remember how excited I was to upgrade
to a 386 with an optical drive. The idea that I could store 650MB available
for download! If I ever needed more I could just change the disk.

Missed many nights of homework working on that thing. Making contests for LoRD
or Tradewars. Zed described the death of BBSs very accurately. It went from
THE thing to do, to lights out almost overnight.

------
endgame
Good timing. I'm working on a MUD server with lua scripting and this coroutine
stuff is a much better way to handle input.

Eventually I'm going to stick ZMQ-based RPC onto it as well, so other services
(M2?) can interrogate the server for things like player lists.

------
quadhome
Use <http://dpaste.de/xtDj/raw/> instead of the given URL.

~~~
zedshaw
Thanks, that also has a bug but people who try it should know how to fix it.
Basically if it bombs because you don't have json then delete the line of code
as it does it correctly further down.

~~~
meric

      Connecting to mongrel2.org:80
      Traceback (most recent call last):
        File "client.py", line 36, in <module>
          post_msg("connect")
        File "client.py", line 28, in post_msg
          msg = '@bbs %s\x00' % (json.dumps({'type': 'msg', 
      'msg': data}))
      AttributeError: 'module' object has no attribute 'dumps'
    

I think it's to do with my python 2.5.

------
osi
web-programming with coroutines has been around.

[http://cocoon.apache.org/2.1/userdocs/flow/continuations.htm...](http://cocoon.apache.org/2.1/userdocs/flow/continuations.html)
for one example, but that was still based on prior art.

------
ggchappell
Figlet "large" font sighted about 20% of the way down. :-)

