Are you looking for Python decorators in Scala? I did look for them when

first studying Scala. I tried to look up for Scala/Java annotations,

as the syntax was too similar to ignore the clue.

But annotations are for adding runtime (reflection accessible) metadata.

As it turned out, Scala usually try to push as much as possible out of language specification to library implementation, and, also in this

case, there are more general, powerful language features to mimic Python

decorators.

Simple Python decorators

Let’s consider the first naive example:

def three_times(wrapped): def wrapping(*args, **kargs): for _ in xrange(3): wrapped(*args, **kargs) return wrapping @three_times def foo(): print "hello!"

this yields:

>>> foo() hello! hello! hello!

In scala you can leverage call by name evaluation strategy to obtain a similar result. Instead of wrapping the entire function, you wrap the function body (or only part of it, when necessary)

scala> def threeTimes(code: =>Unit) = 1 to 3 foreach {_ => code} threeTimes: (code: => Unit)Unit scala> def foo = threeTimes { println("hello!") } foo: Unit scala> foo hello! hello! hello!

In the more general case, call by name is very effective in building customized and powerful control structures (see for the scala actors library

for an example of how scala can be “extended” with specialized control structure).

Also Python’s with statement can be implement using call-by-name.

Decorating recursive functions

There is another way to “decorate” a function, that is useful when

decorating a recursive function. Let’s take the classical Fibonacci function:

def memo(wrapped): cache = {} def wrapping(*args): if args in cache: print "cache hit for %s" % args return cache[args] else: ret = wrapped(*args) cache[args] = ret return ret return wrapping @memo def fib(i): return ( 0 if i == 0 else 1 if i == 1 else fib(i-1) + fib(i-2) )

Note that the call-by-name approach doesn’t work in this case because the memoizing function needs to access memoized function parameters.

Using Scala’s function literals we can do:

object Test { def memo(f: Int=>Int) = new Function1[Int,Int] { var cache = Map[Int,Int]() def apply(i:Int) = if (cache contains i) { println("cache hit for "+i) cache(i) } else { val ret = f(i) cache += (i -> ret) ret } } val fib: Int=>Int = memo { case 0 => 0 case 1 => 1 case n => fib(n-1) + fib(n-2) } }