Archive for July, 2009

Beware of Scala’s lazy Range in for/yield

I’m currently using Scala for most of our development and like it a lot. Coming from a mostly Java background, it is nice with a familiar execution environment and tools. But there a few things that has bitten me, one which I just spend almost an hour trying to nail. So I’m posting it here hoping it might save somebody in the future.

Scala has a nice mechanism for creating lists with a for comprehension:

val l = for (...) yield computeResult(...)

Basically, l will become the list of return values from computeResult. Cool.

Scala also has Range class that, together with the for comprehension mimics a standard for-loop construct:

for(i <- 1 to 20) { ... } [/sourcecode]

Problem

I had the following case. I needed to create some objects in a database and return the results in a list. So I created something that looked like the following:

val databaseObjects = for(i <- 1 to 20) yield { val o = CreateObject o } [/sourcecode] When I ran this code, nothing happened?! I checked the DB, no records to be found anywhere. I tried printing the object o inside the loop. Nothing got printed. Tried the construct in the Scala REPL. Everything worked fine. Then I tried printing databaseObjects.length after the loop. Shows that 20 objects were created. Hmmmm. Then I tried printing all elements of databaseObjects. They were created just fine. Hmmmmm. I recalled  a discussion about the Range being created by the expression "1 to 20" is a lazy data structure which is not evaluated before the results are needed. Turns out this lazyness is contagious (more details can be found here)  Ahhhh. Everything makes sense now, since nothing happened until I tried to actually fetch the objects from the list (and the REPL implicitly retrieves the objects to print out the results!)

Solution

The fix is easy, you need to force the lazy range:

val databaseObjects = for(i <- (1 to 20).force) yield { [/sourcecode]