Rich Dougherty's blog

Thursday, January 28, 2010

Scala 2.8.0 beta 1 released

The first Scala 2.8 beta has been released. It has a lot of new features. I'm particularly looking forward to using the improved collections, type specialization, default arguments, and of course continuations!

The continuations plugin hasn't been merged into the default distribution yet. If you'd like to use continuations with the beta then you'll need to build it yourself.

Building the plugin

The process for building the plugin is pretty much as I described in my original post. One of the JAR files has been moved out of the standard Scala distribution, so you'll need to download it manually (using the second wget below).

First download the Scala 2.8 beta.

$ wget http://www.scala-lang.org/downloads/distrib/files/scala-2.8.0.Beta1-prerelease.tgz
$ tar xzf scala-2.8.0.Beta1-prerelease.tgz
$ wget http://scala-tools.org/repo-releases/org/scala-lang/scala-partest/2.8.0.Beta1/scala-partest-2.8.0.Beta1.jar -O scala-2.8.0.Beta1-prerelease/lib/scala-partest.jar
$ export SCALA_HOME=`pwd`/scala-2.8.0.Beta1-prerelease

Next get the source for the continuations plugin.

$ svn co http://lampsvn.epfl.ch/svn-repos/scala/compiler-plugins/continuations/trunk continuations

Then build it and run the tests.

$ cd continuations
$ ANT_OPTS=-Xmx512m ant test

Finally set an environment variable to point to the continuations code.

$ export CONT_HOME=`pwd`

Compiling and running a program that uses continuations

Here's a short example program that uses continuations.

$ cat > example.scala
import scala.continuations.ControlContext._

object Example {
  def main(args: Array[String]) {
    reset {
      println("first")
      shift { k: (Unit => Unit) => k(k(())) }
      println("last")
    }
  }
}

To compile it you'll need to load the continuations plugin into the compiler.

$ $SCALA_HOME/bin/scalac -Xplugin:$CONT_HOME/build/pack/selectivecps-plugin.jar -classpath $CONT_HOME/build/build.library example.scala

To run it just make sure you include the continuations runtime library.

$ $SCALA_HOME/bin/scala -classpath $CONT_HOME/build/build.library:. Example
first
last
last

And that's it.

Friday, January 22, 2010

Continuations plugin for Scala 2.8 beta

The first Scala 2.8 beta is due to be released soon. Unfortunately the continuations code won't be merged in time for the beta. In the meantime if you want to try out the continuations features then you'll need to build the continuations compiler plugin and support library yourself. In preparation for the beta release I thought I'd post some updated instructions for building the continuations plugin.

Building the plugin

These instructions are based on a recent beta release candidate, but they should also work fine for the actual beta. The process for building the plugin is pretty much as I described in my previous post. The only real change is that you now need to download an additional JAR from the Maven repository, because the JAR is no longer included in the standard Scala distribution.

First download the Scala 2.8 beta. If you want to use a newer release then you'll of course need to update the URLs.

$ wget http://www.scala-lang.org/downloads/distrib/files/scala-2.8.0.Beta1-RC8.tgz
$ tar xzf scala-2.8.0.Beta1-RC8.tgz
$ wget http://scala-tools.org/repo-releases/org/scala-lang/scala-partest/2.8.0.Beta1-RC8/scala-partest-2.8.0.Beta1-RC8.jar -O scala-2.8.0.Beta1-RC8/lib/scala-partest.jar
$ export SCALA_HOME=`pwd`/scala-2.8.0.Beta1-RC8

Next get the source for the continuations plugin.

$ svn co http://lampsvn.epfl.ch/svn-repos/scala/compiler-plugins/continuations/trunk continuations

Then build it and run the tests.

$ cd continuations
$ ANT_OPTS=-Xmx512m ant test

Compiling and running a program that uses continuations

Set an environment variable to point to the continuations code.

$ export CONT_HOME=.../continuations

Here's a short example program that uses continuations.

$ cat > example.scala
import scala.continuations.ControlContext._

object Example {
  def main(args: Array[String]) {
    reset {
      println("first")
      shift { k: (Unit => Unit) => k(k(())) }
      println("last")
    }
  }
}

To compile it you'll need to load the continuations plugin into the compiler.

$ $SCALA_HOME/bin/scalac -Xplugin:$CONT_HOME/build/pack/selectivecps-plugin.jar -classpath $CONT_HOME/build/build.library example.scala

To run it just make sure you include the continuations runtime library.

$ $SCALA_HOME/bin/scala -classpath $CONT_HOME/build/build.library:. Example
first
last
last

Enjoy!

Sunday, April 5, 2009

Tail calls, @tailrec and trampolines

Recursion is an essential part of functional programming. But if each call allocates a stack frame, then too much recursion will overflow the stack. Most functional programming languages solve this problem by eliminating stack frames through a process called tail-call optimisation. Unfortunately for Scala programmers, the JVM doesn't perform this optimisation.

Here's a picture of a Scala program as it executes. This program tries to work out whether 9999 is even or odd by calling odd1 and even1 recursively. The stack overflows before we can make 9999 calls.

def odd1(n: Int): Boolean = {
  if (n == 0) false
  else even1(n - 1)
}
def even1(n: Int): Boolean = {
  if (n == 0) true
  else odd1(n - 1)
}
even1(9999)

All the calls in our example program are in tail position, so if the JVM did support tail-call optimisation, then the program would be able to complete successfully.

Luckily, even without JVM support, the Scala compiler can perform tail-call optimisation in some cases. The compiler looks for certain types of tail calls and translates them automatically into loops. At the moment it can optimise self calls in final methods and in local functions. It cannot optimise non-final methods (because they might be overridden by a subclass), and it cannot optimise tail calls that are made to different methods.

What this means

Because of these limitations, you need to be careful when using recursion in Scala. When writing programs, you will need to keep in mind how both the compiler and the JVM work. One safe approach is to use code from the standard library, where possible. For example, you'll find that many recursive algorithms can easily be rewritten in terms of standard operations like map and fold.

In Scala 2.8, you will also be able to use the new @tailrec annotation to get information about which methods are optimised. This annotation lets you mark specific methods that you hope the compiler will optimise. You will then get a warning if they are not optimised by the compiler. In Scala 2.7 or earlier, you will need to rely on manual testing, or inspection of the bytecode, to work out whether a method has been optimised.

If you do find a call that you think should be optimised by the compiler, but isn't, then you should check that the call:

  1. is a tail call,
  2. is in a final method or local function, and
  3. is to itself.

For example, the code for factorial below would not be optimised. The call is not in tail position (the tail operation is the multiplication), and the method is public and non-final, so it could be overridden by a subclass.

class Factorial1 {
  def factorial(n: Int): Int = {
    if (n <= 1) 1
    else n * factorial(n - 1)
  }
}

You can make simple changes to factorial to eliminate both of these problems. First, you could move the recursive code into a local function within the method, so that it cannot be overridden. Second, you could introduce an accumulator so that multiplication happens before the recursive call. Finally, you could add a @tailrec annotation so that you can be sure that your changes have worked.

import scala.annotation.tailrec

class Factorial2 {
  def factorial(n: Int): Int = {
    @tailrec def factorialAcc(acc: Int, n: Int): Int = {
      if (n <= 1) acc
      else factorialAcc(n * acc, n - 1)
    }
    factorialAcc(1, n)
  }
}

But there are some types of recursive code that the compiler will not be able to optimise. For example, if your code is mutually recursive, as it is with odd1 and even1, then you will need to try something else. One thing you might consider, is using a trampoline.

Trampolines

A trampoline is a loop that repeatedly runs functions. Each function, called a thunk, returns the next function for the loop to run. The trampoline never runs more than one thunk at a time, so if you break up your program into small enough thunks and bounce each one off the trampoline, then you can be sure the stack won't grow too big.

Here is our program again, rewritten in trampolined style. Call objects contain the thunks and a Done object contains the final result. Instead of making a tail call directly, each method now returns its call as a thunk for the trampoline to run. This frees up the stack after each iteration. The effect is very similar to tail-call optimisation.

def even2(n: Int): Bounce[Boolean] = {
  if (n == 0) Done(true)
  else Call(() => odd2(n - 1))
}
def odd2(n: Int): Bounce[Boolean] = {
  if (n == 0) Done(false)
  else Call(() => even2(n - 1))
}
trampoline(even2(9999))

It only takes a few lines of code to implement a trampoline.

sealed trait Bounce[A]
case class Done[A](result: A) extends Bounce[A]
case class Call[A](thunk: () => Bounce[A]) extends Bounce[A]

def trampoline[A](bounce: Bounce[A]): A = bounce match {
  case Call(thunk) => trampoline(thunk())
  case Done(x) => x
}

Trampolined code is harder to read and write, and it executes more slowly. However, trampolines can be invaluable when your program would otherwise run out of stack space, and the only other alternative is to convert it into an imperative style. There has recently been talk of including a trampoline implementation in Scala 2.8. (The code in this article is based on the code from that discussion.)

Postscript: Continuations

I've been writing about continuations quite a bit recently, so I think it's fitting to mention their relationship to trampolines. It turns out that a thunk can be easily manufactured from a continuation. You can create thunks automatically using shift and reset. In fact my recent implementation of goto used a form of trampoline. I'll close here by showing how goto can be implemented using the trampoline that we defined above.

import scala.continuations.cps
import scala.continuations.ControlContext.{shift,reset}

def trampolineK[A,B1<:C,C1<:C,C](body: => B1 @cps[B1,Bounce[C1]]): C =
  trampoline(reset(Done(body)))

case class Label[A](k: Label[A] => Bounce[A])

def label[A]: Label[A] @cps[Bounce[A],Bounce[A]] =
  shift((k: Label[A] => Bounce[A]) => k(Label(k)))

def goto[A](l: Label[A]): Unit @cps[Bounce[A],Bounce[A]] =
  shift((k: Nothing => Bounce[A]) => Call(() => l.k(l)))

trampolineK {
  var sum = 0
  var i = 0
  val beforeLoop = label
  if (i < 10000) {
    println(i)
    sum += i
    i += 1
    goto(beforeLoop)
  }
  println(sum)
}

Update: Fixed image scaling.