The Scala for-loop translation scheme

If you're interested in the details of the translation scheme of a Scala for loop (for comprehension), here's a quick look at how a for loop is translated into, well, other code.

.
.
.
.

A simple Scala for loop

In a first example, we'll start with the following Scala class:

class Main {
  def foo { for(i <- 0 to 10) println(i) }
}

Next, I compile this class from the command line like this:

$ scalac -Xprint:all Main.scala 

This command produces a ton of output, maybe 50-100 lines of output or more. Digging through the output, we can see how the simple for loop is translated. Here's the first translation, where you can see the for loop is translated into a foreach method call:

def foo: scala.Unit = 0.to(10).foreach(((i) => println(i)))

Digging through the output, the next translation looks like this:

def foo: Unit = scala.this.Predef.intWrapper(0).to(10).foreach[Unit](((i: Int) => scala.this.Predef.println(i)))

That's basically the same as the first step, but more specific about each element in the expression. After this, the code quickly explodes into something much larger:

def foo(): Unit = scala.this.Predef.intWrapper(0).to(10).foreach[Unit]({
  @SerialVersionUID(0) final <synthetic> class $anonfun extends scala.runtime.AbstractFunction1[Int,Unit] with Serializable {
    def <init>(): anonymous class $anonfun = {
      $anonfun.super.<init>();
      ()
    };
    final def apply(i: Int): Unit = scala.this.Predef.println(i)
  };
  (new anonymous class $anonfun(): Int => Unit)
})

The code continues to grow like this, but rather than show it all here, I encourage you to run the scalac command I showed above.

An important thing you can see from this simple example is that our simple for loop is translated into a foreach method call.

A slightly more complicated example

Next, let's take a look at a slightly more complicated example where I add a simple if statement (guard) to a for comprehension. Here's the source code for the Scala class:

class Main {

  def foo {
    for { i <- 0 to 10
          if i % 2 == 0
    } println(i)
  }

}

Again I'll compile the source code with this command:

$ scalac -Xprint:all Main.scala 

Next, sifting through the output, we can see that the source code is initially translated to this:

def foo: scala.Unit = 0.to(10).withFilter(((i) => i.$percent(2).$eq$eq(0))).foreach(((i) => println(i)))

With more sifting through the output, we can see that this statement is translated into this code:

def foo: Unit = scala.this.Predef.intWrapper(0).to(10).withFilter(((i: Int) => i.%(2).==(0))).foreach[Unit](((i: Int) => scala.this.Predef.println(i)))

Again, after this step the code gets much more complicated, and rather than show it all here, I'll leave it at that.

As you can see from this example, the initial Scala source code has been translated into a withFilter call, which uses a foreach statement.

Comparing the two examples

At this point it's fun and interesting to compare the output from the two examples. Here's the output from the first step of the translated code for each example:

// 1) the simple for loop
def foo: scala.Unit = 0.to(10).foreach(((i) => println(i)))

// 2) the for comprehension with one 'if' statement
def foo: scala.Unit = 0.to(10).withFilter(((i) => i.$percent(2).$eq$eq(0))).foreach(((i) => println(i)))

As you can see, the first example results in a direct translation from a for loop to a foreach call on our Range, while the second example results in a withFilter method call on our Range, with a foreach statement used in the code in the filter.

More Scala translation information

For more information on how Scala source code is translated during the compilation process, see the Scala Language Specification at the following URL:

Pages 97-98 of the current specification has this information about the Scala for loop translation scheme:

A for loop for (enums) e executes expression e for each binding generated by the enumerators enums. A for comprehension for (enums) yield e evaluates expression e for each binding generated by the enumerators enums and collects the results. An enumerator sequence always starts with a generator; this can be followed by further generators, value definitions, or guards.

A generator p <- e produces bindings from an expression e which is matched in some way against pattern p. A value definition "p = e" binds the value name p (or several names in a pattern p) to the result of evaluating the expression e. A guard if e contains a boolean expression which restricts enumerated bindings. The precise meaning of generators and guards is defined by translation to invocations of four methods: map, withFilter, flatMap, and foreach. These methods can be implemented in different ways for different carrier types.

The translation scheme is as follows...

At this point the specification lays out the rules for the translation scheme, and I encourage you to look at the specification (linked to above) for these details.