Why does Scala need parameterless in addition to zero-parameter methods?

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 :-)

Leave a Comment