From: "Jörg W Mittag" Date: 2009-04-21T15:45:05+09:00 Subject: Re: Move over, Phusion, here comes the *real* Enterprise Edition! I'm three weeks late, but I just *had* to drop my 2 cents here ... M. Edward (Ed) Borasky wrote: > On Wed, Apr 1, 2009 at 6:00 AM, Charles Oliver Nutter > wrote: >> Well, according to the earliest drafts of the Ruby standard, continuations >> are not part of "core Ruby" :) >> >> But yes, this is one area we've opted not to be compatible in exchange for >> performance. We could implement continuations, but we'd be several times >> slower as a result. > IIRC YARV also dropped continuations because they would be slow on the > YARV VM as well. They are still there, just no longer in the core library. They have been "downgraded" to the stdlib. They *had been* removed for a pretty long period of time, but they reappeared. In fact, for almost two years, it was actually said to be *impossible* to implement them on YARV, but then without much fanfare, the continuation library appeared in a CVS commit. > Which does raise an interesting point, though. Call/cc has been > standard equipment on Scheme for years and nobody has complained about > performance. How did Ruby manage to paint itself into a "slow > continuation" corner? I don't think the problem is Ruby. The problem is the implementations. You can implement continuations really really slow in Scheme, too, if you only implement it badly enough. And there is a lot of bad Scheme implementations out there. In MRI, continuations are slow (and apparently they leak memory like there's no tomorrow), because MRI is, quite frankly, a bad implementation. Continuations are only one example; the garbage collector, the extension API, the (non-existent) FFI, the fact that concurrency isn't actually concurrent, are others. And Matz himself has made it very clear that he does not consider MRI to be a good implementation, he has always pointed out that he is primarily a language designer and not necessarily a programmer and *definitely* not a VM guru. In YARV, continuations are faster and the memory leaks are plugged, but they aren't really fast, either. In this case, it's a design decision: they weren't *meant* to be fast, indeed, they weren't meant to implemented *at all*. And JRuby, well, to paraphrase Clojure's Rich Hickey (he was talking about tail calls, but it applies equally to continuations): "Java interoperability. High performance. Continuations. Pick any two." This applies not only to continuations and tail calls but really *everything* that doesn't fit the linear call stack paradigm (like coroutines). And it also doesn't only apply to Java, but also to .NET and even C. The problem arises when you want to implement advanced control flow constructs on execution engines that don't support them natively. Basically, all you need to implement advanced control flow is either continuations or reified call stacks. Java has neither. So, you are left with a couple of choices: use continuation-passing-style, implement your own stack or use exceptions for control flow. Or, well, just give up. CPS and managing your own stack both mean that you are no longer call stack compatible with Java, which complicates (and slows down) Java interop. Using exceptions isn't really performant, although exceptions are much faster on Java than people give them cedit for, but this particular usage pattern doesn't fit with the optimizations. JRuby and IronRuby chose to emphasize performance and interop and sacrifice continuations. Even Rubinius is currently converting from a self-managed spaghetti stack to just the plain C stack, even though that severely complicates Rubinius's distinctive "stackless" features like reified stack frames, lightweight tasks, continuations, actors and threads, and embeddability and multi-VM. One of the reasons is again interop, this time with C (FFI). The Parrot VM on the other hand, has continuations as its *only* control flow mechanism built deeply into the VM. Squeak has reified stack frames, thus allowing Seaside to implement continuations in the library, even though Squeak doesn't support them. I suspect similar things might be true for MagLev, especially since they are actually willing to change the VM to fit Ruby. jwm