Currying, That’s Why
Daniel did a great job at explaining why parameterless methods are necessary. I’ll explain why they are regarded distinctly from zero-parameter methods.
Many people view the distinction between parameterless and zero-parameter functions as some vague form of syntactic sugar. In truth it is purely an artifact of how Scala supports currying (for completeness, see below for a more thorough explanation of what currying is, and why we all like it so much).
Formally, a function may have zero or more parameter lists, with zero or more parameters each.
This means the following are valid: def a
, def b()
, but also the contrived def c()()
and def d(x: Int)()()(y: Int)
etc…
A function def foo = ???
has zero parameter lists. A function def bar() = ???
has precisely one parameter list, with zero parameters. Introducing additional rules that conflate the two forms would have undermined currying as a consistent language feature: def a
would be equivalent in form to def b()
and def c()()
both; def d(x: Int)()()(y: Int)
would be equivalent to def e()(x: Int)(y: Int)()()
.
One case where currying is irrelevant is when dealing with Java interop. Java does not support currying, so there’s no problem with introducing syntactic sugar for zero-parameter methods like "test".length()
(which directly invokes java.lang.String#length()
) to also be invoked as "test".length
.
A quick explanation of currying
Scala supports a language feature called ‘currying’, named after mathematician Haskell Curry.
Currying allows you to define functions with several parameter lists, e.g.:
def add(a: Int)(b: Int): Int = a + b
add(2)(3) // 5
This is useful, because you can now define inc
in terms of a partial application of add
:
def inc: Int => Int = add(1)
inc(2) // 3
Currying is most often seen as a way of introducing control structures via libraries, e.g.:
def repeat(n: Int)(thunk: => Any): Unit = (1 to n) foreach { _ => thunk }
repeat(2) {
println("Hello, world")
}
// Hello, world
// Hello, world
As a recap, see how repeat
opens up another opportunity to use currying:
def twice: (=> Any) => Unit = repeat(2)
twice {
println("Hello, world")
}
// ... you get the picture :-)