1

In Python I can do this:

In [24]: def m1():
   ....:     return "I am legend"
   ....: 

In [25]: f1 = m1

In [26]: type(f1)
Out[26]: function

In [27]: type(m1)
Out[27]: function

while in Scala,

def m1() = "I am legend"

the equivalent of what I did above is not

val f1 = m1

but I instead have to specify

scala>  val f1:()=> String = m1
f1: () => String = <function0>

or

scala>  val f1 = m1 _
f1: () => String = <function0>

Why was this design choice made ? As someone coming to Scala from Python, being able to assign a function via

val f1 =  m1

seems much more natural than having to do one of the approaches above.

I know that val f1 = m1

results in m1 being called and the resulting value assigned to f1 but wouldn't it have been clearer to follow the Python approach and require the parenthesis in this case instead i.e.

val f1 = m1()

in the case where I wish to call the function and assign the result to f1 ?

femibyte
  • 3,317
  • 7
  • 34
  • 59
  • 3
    This was a design choice. Allowing methods of arity-0 to omit parenthesis means that `val f1 = m1` can't be both method invocation and function assignment. Like most things, it's a trade-off. The designers likely though omitting parenthesis would be more useful as it would happen more than assigning methods to functions. – Yuval Itzchakov May 22 '16 at 09:48
  • @YuvalItzchakov it seems implausible that functional programming language designers would believe omitting parenthesis on a function call (which is often a sign of nasty side effects in Scala) would be more common than assigning methods to functions (which is a hallmark usage pattern of functional programming to such an extent that it might even be considered partly a defining property of functional programming languages). – ely Nov 15 '18 at 14:24
  • @ely It might, but don't forget Scala isn't only a functional programming language, it's a *hybrid* language, where a decent portion of people on boarding it have an OOP background. Also, omitting parenthesis from a function means exactly the opposite of what you said, it should only happen for *pure* methods. – Yuval Itzchakov Nov 15 '18 at 17:09
  • @ely I understand what you're saying, but I'm not sure what it has to do with the fact I stated above regarding eta expansion? – Yuval Itzchakov Nov 15 '18 at 19:57

1 Answers1

1

In Scala, you should omit parentheses if the method has no side effects which greatly improves readability. Quote from Scala docs:

Scala allows the omission of parentheses on methods of arity-0 (no arguments). However, this syntax should only be used when the method in question has no side-effects (purely-functional). In other words, it would be acceptable to omit parentheses when calling queue.size, but not when calling println(). This convention mirrors the method declaration convention given above.

Religiously observing this convention will dramatically improve code readability and will make it much easier to understand at a glance the most basic operation of any given method. Resist the urge to omit parentheses simply to save two characters!

There are some deeper considerations on on this concerning uniform access principle. They are expounded in Martin Odersky et al "Programming in Scala" book, section 10.3. I will not quote it here (it is more than two pages long), but the point is that omitting parentheses while calling arity-0 methods allows you to change those methods into vals seamlessly, without even touching client's code. Doing so, you manage the usual time-space tradeoff. In particular, you can override defs with vals (but not vice-versa):

abstract class Mass {
  def kilograms: Double
}

class Grams(grams: Double) extends Mass {
  val kilograms: Double = {
    Thread.sleep(5000) // pretend to think hard
    grams / 1000.0
  }
}

More on def vs val vs lazy val

Of course, all this stuff wouldn't be possible if python-like assignment was allowed.

Community
  • 1
  • 1
ars
  • 1,509
  • 3
  • 18
  • 29
  • It always kills me when people mention the concept of "no side effects." The runtime of a 0-arity function is always a side effect, for example. If the parentheses are used, then you know a procedure is invoked. Maybe it's the very first time that some expensive attribute is retrieved from disk or something. There may be no side-effects at all (every time you call the function it always gives the same static result), but there could be side effects in terms of what resources are consumed to do it, whether it was memoized on the first try for example. – ely Nov 15 '18 at 14:27
  • It's incredibly foolish to believe that uniform access principle has anything to do with side effects. Turning method call results into static attributes, even if the content of the result does not change, is inherently always potentially side-effectful at all times and the programmer needs to be able to reason about that and possible handle it or guard against it (e.g. polling for whether a 0-arity function call has completed yet and generating a timeout error if needed). – ely Nov 15 '18 at 14:29