Personal tools
You are here: Home Members martin Martins Weblog To Type Or Not To Type - Functions in Scala and Groovy
Document Actions
  • Print this page
  • Add Bookmarklet

To Type Or Not To Type - Functions in Scala and Groovy

Does a static type system help even though the code becomes longer / more ugly?

Continuing my exploration of Groovy and Scala I have finished chapter 8 of "Programming in Scala", which is on functions and closures. Most of the function / closure stuff is not that surprising. Which means that this blog entry will be rather short.

Nested functions

Scala supports nested function declarations, that is named functions declared within a named function. These have access to the names in the enclosing function(s). Nested functions are useful, when you have functions that are only useful in a limited context to improve readability. In this case it is also nice that you do not have to pass parameters explicitly from the outer function to the inner one. Program layout then resembles the call hierarchy.

def testNested() {
val context=5
def foo(i: Int) = i + context
assertEquals(8, foo(3))
}

In this example (part of a JUnit test case) testNested sets up some execution context for the inner function and then evaluates it. No need to define "context" as a parameter to "foo".

Groovy does not support nested function declarations. I think Pascal had them and I missed them a lot when I started to program C about 1990. But if you really need them, you can emulate nested functions using closures in Groovy, see below.

Closures

Both Scala and Groovy allow for anonymous functions. In both languages these are not only allowed to refer to parameters but also to refer to variables in scope when the function is defined, thus creating closures. In Groovy you can always omit the parameter types. In Scala you often have to define the parameter types.

// Scala
val incr = (i: Int) => i + 1
assertEquals(2, incr(1))
// Groovy
def incr = { x -> x + 1 }
assertEquals(2, incr(1))

Note the syntactical similarity. Scala defines anonymous functions with the double arrow and calls them "function literals", Groovy uses curly braces with single arrow and calls them "closures". Here I find it easier to read the Groovy variant, partially because the type can be left out.

Both languages support shortcuts for anonymous function definitions.

Groovy allows to drop the parameter declaration and arrow when the function takes only a single parameter, which is then called "it" implicitly:

// Groovy
def incr = { it + 1 }
assertEquals(2, incr(1))

Scala allows to drop the parameter list and arrow when the parameters are only used once. Every parameter is then replaced by an underscore. The parameter types are then declared inline.

// Scala
val incr = (_: Int) + 1
val add = (_: Int) + (_: Int)
assertEquals(2, incr(1))
assertEquals(7, add(3, 4))

The Scala code looks a little bit ugly, or at least strange. What do you get for the additional typing? Better content assist in Eclipse for example. Better byte code, because the compiler has more knowledge on which methods are going to be called. Less stupid errors, when applying functions to unsupported actual arguments. On the other hand, duck typing also has its merits.

Fortunately the parameter type declarations can be omitted in Scala, too, provided that the compiler can infer the types automatically from the context.

// Scala
val someNumbers = List(-1, 0, 1, 2)
assertEquals(List(-1), someNumbers.filter(x => x < 0))
// or, because x is used only once in the function literal:
assertEquals(List(-1), someNumbers.filter(_ < 0))

This again looks very similar to equivalent Groovy code:

// Groovy
def someNumbers = [ -1, 0, 1, 2 ]
assertEquals([-1], someNumbers.findAll{it < 0})

One important difference: Scala is type checked. Assume you type + instead of < in the predicate closure above. Scala won't compile: You get "type mismatch, found: Int required: Boolean". In Groovy you get something else...

// Broken Groovy
def someNumbers = [ -1, 0, 1, 2 ]
assertEquals([-1, 1, 2], someNumbers.findAll{it + 0})
// ~~~~~~ means it != 0

I don't want to stress this to much, because there are enough other possibilities to make errors that pass type checking, but the combination of Groovy Booleans and missing static type system is generating really strange effects, here.

Partial Application of Functions

Both languages support partial application of functions, that is, creating a new function by binding only some of the function parameters, but not all. The result is a new function with the remaining unbound parameters. This sounds strange when you hear this concept for the first time, but has some interesting real-world applications. Missed that feature the day before in Java and had to define some anonymous inner classes with 90% syntax and 10% functionality instead.

The concept is called "currying" or, in German "schönfinkeln", referring to the inventors of the concept. Groovy can only bind the leftmost parameter of a function when currying, Scala supports binding arbitrary parameters.

// Groovy
def add = { a, b -> a + b }
def incr = add.curry(1)

"incr" is a closure with a single parameter that adds 1 (the parameter to "curry") to its parameter when applied. Possibly also interesting: I used the closure syntax to emulate a local function definition (see above) for "add".


// Scala
def add(a: Int, b: Int) = a + b
val incr = add(1, _: Int)// Scala

def sub(a: Int, b: Int) = a - b
val decr = sub(_: Int, 1)
assertEquals(2, decr(3))

The "incr" definition is essentially the same in Scala, slightly better readable because of syntax support for currying (the underscore denotes an unbound parameter, that is the parameter for the resulting function. The value 1 in bound to the first parameter of add, the second parameter stays unbound, resulting in a function with one parameter.

The "decr" definition above is not possible using currying in Groovy, because it binds the second parameter of "sub".

Tail recursion optimization

Scala supports tail recursion optimization, that is the transformation of a recursive function into iterative code, provided that the recursive call is the last statement in the recursive function. You might think of the callee borrowing the stack frame of the caller because the caller does not need it anymore since it is about to return.

In Scala the tail recursion optimization is only done when directly calling the same named function. Indirect recursion or calling throug curried functions will not be optimized, according to the book. This is more than Java does (nothing) but less than other languages. The reason seems to be a restriction of the JVM. I'll have to see which limitation this is in practice.

Conclusion

Just taking the visual appearance of the code, Groovy and Scala both do well for function literals / closures. I prefer the underscore as wildcard character to the magical "it" parameter and the half-hearted currying support of Groovy. On the other hand I somewhat dislike the syntax for supplying the type information for function literals in Scala.

I do not know the additional API calls for either language. The static type system and resulting IDE support makes it easier to find candidate API calls in Scala through code completion. I almost wrote that I assume Scala to be faster than Groovy thanks to the type system, but without any benchmark this is not a valid statement.

No, this was not so short. But fun to write.

_____
tags:
Friday, November 07, 2008 in Programming Languages  | Permalink |  Comments (0)
Martins Weblog
« January 2009 »
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Recent entries:
No Closures in Java 7?
iPhone bei simyo
Limited Visibility
To Type Or Not To Type - Functions in Scala and Groovy
Rational Numbers in Scala
More...
Categories:
Programming Languages (5)
Technology (3)
blogging (1)
fun (1)
model-driven development (1)
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: