This is the mail archive of the
kawa@sourceware.org
mailing list for the Kawa project.
using java.lang.Throwable for flow control (was: Re: SLIME backend)
On Wednesday 28 May 2008 05:23:30 pm Helmut Eller wrote:
> * Jim White [2008-05-28 17:47+0200] writes:
> > > [BTW, I always wonder how expensive fillInStackTrace is. Is
> > > there a trick to make this cheap or is it as expensive as it
> > > sounds?]
> >
> > It's expensive but optional.
>
> [Hmm, I guess a efficiency minded guy could override
> fillInStackTrace with a noop in his custom throwables indented for
> control transfers only. I wonder if Kawa does that for call/cc.]
Efficiency-minded guys do precisely that.
To lift a quote from the following paper:
Event-Based Programming without Inversion of Control
Philipp Haller and Martin Odersky
http://lampwww.epfl.ch/~odersky/papers/jmlc06.pdf
| To save information about statements following 'receive', we would
| need to save the call-stack, or capture a (first-class)
| continuation. Virtual machines such as the JVM provide no means
| for explicit stack management, mainly because of security
| reasons. Thus, languages implementing first-class continuations
| have to simulate the run-time stack on the heap which poses
| serious performance problems. Moreover, programming tools such as
| debuggers and profilers rely on run-time information on the native
| VM stack which they are unable to find if the stack that programs
| are using is allocated on the heap. Consequently, existing tools
| cannot be used with programs compiled using a heap-allocated
| stack.
|
| Thus, most ports of languages with continuation support
| (e.g. Scheme, Ruby) onto non-cooperative virtual machines abandon
| first-class continuations altogether (e.g. JScheme, JRuby). Scala
| does not support first-class continuations either, primarily
| because of compatibility and interoperability issues with existing
| Java code.
|
| To conclude, managing information about statements following a
| call to 'receive' would require changes either to the compiler or
| the VM. Following our rationale for a library-based approach, we
| want to avoid those changes.
|
| Instead, we require that receive *never returns normally*.
|
| ...
|
| For this, the blocking receive throws a special exception of type
| Done (see below) which is caught in the send method (!).
| Technically, this trick unwinds the callstack up to the point
| where the message 'send' transferred control to A.
Last I looked, Done.scala was coded like this:
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/Done.scala?view=markup&rev=8159
| $ svn co -q -r8159 http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk/src/actors/scala/actors/
| $ cat -n actors/Done.scala
| 1 /* __ *\
| 2 ** ________ ___ / / ___ Scala API **
| 3 ** / __/ __// _ | / / / _ | (c) 2005-2006, LAMP/EPFL **
| 4 ** __\ \/ /__/ __ |/ /__/ __ | **
| 5 ** /____/\___/_/ |_/____/_/ | | **
| 6 ** |/ **
| 7 \* */
| 8
| 9 // $Id: Done.scala 8159 2006-07-14 12:45:15Z phaller $
| 10
| 11 package scala.actors
| 12
| 13 /**
| 14 * @author Philipp Haller
| 15 */
| 16 class Done extends Throwable {
| 17 override def fillInStackTrace(): Throwable =
| 18 this;
| 19 }
They must've rewritten it in the past two years. I no longer see
Done.scala in the repository:
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors?rev=15401
But the trick of overriding fillInStackTrace() lives on:
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/actors/scala/actors/Actor.scala?rev=15219#L945