Scala Lambdas

A lambda or, more specifically a lambda expression is a term used to refer to an expression that does not reference a value or variable, but instead references an anonymous function.

Scala supports the idea of lambda expressions quite nicely, and in several different forms, but it’s easy to confuse them with other similar constructs, like closures.

Why?

There are a few reasons most people use lambda expressions:

Convenience

For a simple function that is used only in one place, a lambda is quicker and easier, and more expressive, than the alternative of declaring a whole function. There are places where a function with a name is more expressive, though, so lambdas shouldn’t be used when they would obscure intent.

Decoupling

Passing a lambda can allow different aspects of an application to be more fully decoupled from each other: one component doesn’t need to know the “internals” or names inside some other component, only the signature of the lambda that is to be passed.

Reusability

Especially in functional programming, using lambdas can allow us to create highly re-usable pieces of code. A very simple example might be a function that can iterate over a list of objects and apply some transformation to them. The transformation doesn’t need to be known at compile time, only the signature of the transformation. This means our function can be re-used for any kind of transformation. (Of course, this is too simple an example, as this is pretty much what the map function built in to Scala does, but you get the idea).

How?

Lambdas in Scala are pretty simple in syntax: they are defined by their function signature. Lets look at this in the Scala REPL:

scala> (l: Long) =< l * l
res0: Long =&gt; Long = &lt;function1&gt;

The REPL reports correctly that we have defined a function that takes a single Long and returns a Long (in this case, the square of the parameter)

We can put this to use like so:

scala> val x = (l: Long) => l * l
x: Long => Long = <function1>

scala> List(1l, 2l, 3l).map(x)
res2: List[Long] = List(1, 4, 9)

Or, more compactly:

scala> List(1l, 2l, 3l).map((l: Long) => l * l)
res3: List[Long] = List(1, 4, 9)

In this case we’re declaring the Lambda right inline, which doesn’t allow the best re-use, but might be more expressive in some cases.

Of course, we can go all the way to the most compact form:

scala> List(1l, 2l, 3l).map(l => l * l)
res5: List[Long] = List(1, 4, 9)

A lambda can also be used as a parameter to a function, and in this form is much more valuable for decoupling and re-use, like so:

scala> def transformedSum(original: List[Long], f: (Long) => Long) = original.map(f).sum
transformedSum: (original: List[Long], f: Long => Long)Long

In this case the “f” parameter of transformedSum expects a function that transforms one long into another Long. The function then applies whatever transformation it is told to by “f” to each value in a list of Longs, then returns the sum of the result.

We can call the function with different lambdas to change it’s behaviour easily:

scala> transformedSum(List(1l, 2l, 3l), (l: Long) => l * l)
res7: Long = 14

Or, with a different lambda:

scala> transformedSum(List(1l, 2l, 3l), (l: Long) => l * 2)
res8: Long = 12

Or even:

scala> transformeadSum(List(1l, 2l, 3l), l => l)
res10: Long = 6

Lambda vs. Closure

While a lambda is essentially the same as a function, taking parameters and returning a value, a closure is a slightly different beast: It “closes over” a scope, and may have access to values declared in that scope that are not explicitly passed as parameters.

For example, here’s a very simple closure in use:

val maxRate = 100
val someValues = List(2, 4, 6, 8, 10)
someValues.map(value => {
  val factor = computeFactor(value)
  callSomeOtherThing(value, maxRate)
})

The closure is everything from the open brace in the “map” line to the close brace. As you can see, the value of “maxRate”, defined outside the closure, is used inside the closure – a key difference.

A closure, therefore, might be only valid in a specific context, whereas a lambda or anonymous function can be reused without regard to the context, as everything it needs to know to do it’s business is passed in as parameters.

Scala Lambdas

As you can see from this very quick introduction, lambdas can be applied in many different ways in Scala – we’ve only touched on a few here. They can also make testing and refactoring easier, and allow mocks or stubs to be easily created for test-time, but that’s another post icon smile Scala Lambdas

Principles and Practices

Tired of the Software Development Grind? Know it can be done better? Check out my book (almost finished!): Principles and Practices of Software Craftsmanship or sign up for my Craftsmanship Dispatches newsletter.

Published: September 12 2013