Given the following constructs for defining a function in Scala, can you explain what the difference is, and what the implications will be?
def foo = {}
vs.
def foo() = {}
Update
Thanks for the quick responses. These are great. The only question that remains for me is:
If I omit the parenthesis, is there still a way to pass the function around? This is what I get in the repl:
scala> def foo = {}
foo: Unit
scala> def baz() = {}
baz: ()Unit
scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit
scala> test(foo)
<console>:10: error: type mismatch;
found : Unit
required: () => Unit
test(foo)
^
scala> test(baz)
res1: () => Unit = <function0>
Update 2012-09-14
Here are some similar questions I noticed:
Difference between function with parentheses and without
Scala methods with no arguments
If you include the parentheses in the definition you can optionally omit them when you call the method. If you omit them in the definition you can't use them when you call the method.
scala> def foo() {}
foo: ()Unit
scala> def bar {}
bar: Unit
scala> foo
scala> bar()
<console>:12: error: Unit does not take parameters
bar()
^
Additionally, you can do something similar with your higher order functions:
scala> def baz(f: () => Unit) {}
baz: (f: () => Unit)Unit
scala> def bat(f: => Unit) {}
bat: (f: => Unit)Unit
scala> baz(foo)
scala> baz(bar)
<console>:13: error: type mismatch;
found : Unit
required: () => Unit
baz(bar)
^
scala> bat(foo)
scala> bat(bar) // both ok
Here baz will only take foo() and not bar. What use this is, I don't know. But it does show that the types are distinct.
Let me copy my answer I posted on a duplicated question:
A Scala 2.x method of 0-arity can be defined with or without parentheses (). This is used to signal the user that the method has some kind of side-effect (like printing out to std out or destroying data), as opposed to the one without, which can later be implemented as val.
See Programming in Scala:
Such parameterless methods are quite common in Scala. By contrast, methods defined with empty parentheses, such as def height(): Int, are called empty-paren methods. The recommended convention is to use a parameterless method whenever there are no parameters and the method accesses mutable state only by reading fields of the containing object (in particular, it does not change mutable state).
This convention supports the uniform access principle [...]
To summarize, it is encouraged style in Scala to define methods that take no parameters and have no side effects as parameterless methods, i.e., leaving off the empty parentheses. On the other hand, you should never define a method that has side-effects without parentheses, because then invocations of that method would look like a field selection.
Terminology
There are some confusing terminology around 0-arity methods, so I'll create a table here:
Programming in Scala
scala/scala jargon
def foo: Int
parameterless methods
nullary method
def foo(): Int
empty-paren methods
nilary method
I sounds cool to say "nullary method", but often people say it wrong and the readers will also be confused, so I suggest sticking with parameterless vs empty-paren methods, unless you're on a pull request where people are already using the jargons.
() is no longer optional in Scala 2.13 or 3.0
In The great () insert, Martin Odersky made change to Scala 3 to require () to call a method defined with (). This is documented in Scala 3 Migration Guide as:
Auto-application is the syntax of calling a nullary method without passing an empty argument list.
Note: Migration document gets the term wrong. It should read as:
Auto-application is the syntax of calling a empty-paren (or "nilary") method without passing an empty argument list.
Scala 2.13, followed Scala 3.x and deprecated the auto application of empty-paren methods in Eta-expand 0-arity method if expected type is Function0. A notable exception to this rule is Java-defined methods. We can continue to call Java methods such as toString without ().
To answer your second question, just add an _:
scala> def foo = println("foo!")
foo: Unit
scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit
scala> test(foo _)
res10: () => Unit = <function0>
scala> test(foo _)()
foo!
scala>
I would recommend always start definition with a function like:
def bar {}
and only in cases, when you are forced, to change it to:
def bar() {}
Reason: Let's consider these 2 functions from a point of possible usage. How they can be infoked AND where they can be passed.
I would not call this a function at all:
def bar {}
It can be invoked as:
bar
but not as a function:
bar()
We can use this bar when we define a higher-order function with a call-by-name parameter:
def bat(f: => Unit) {
f //you must not use (), it will fail f()
}
We should remember, that => Unit - is not even a function. You absolutely cannot work with a thunk as if it's a function insofar as you cannot choose to treat it as Function value to be stored or passed around. You can only trigger evaluations of the actual argument expression (any number of them).
Scala: passing function as block of code between curly braces
A function, defined with () has a bigger scope for usage. It can be used exactly, in the same context, as bar:
def foo() = {}
//invokation:
foo
//or as a function:
foo()
It can be passed into a function with a call-by-name parameter:
bat(foo)
Additionally, if we define a higher-order function, that accepts not a call-by-name pamameter, but a real function:
def baz(f: () => Unit) {}
We can also pass foo to the baz:
baz(foo)
As we can see standard functions like foo have a bigger scope for usage. But using a functions defined without () plus defining higher-order functions, that accept call-by-name parameter, let us use more clear syntax.
If you do not try to archive a better, more readable code, or if you need ability to pass your piece of code both to function defined with a call-by-name parameter and to a function defined with a real function, then define your function as standard one:
def foo() {}
If you prefer to write more clear and readable code, AND your function has no side-effects, define a function as:
def bar {}
PLUS try to define your higher-order function to accept a call-by-name parameter, but not a function.
Only when you are forced, only in this case use the previous option.
Related
I have the following code.
object example {
def foo(a: Any) = "Object"
def foo(a: String, args: String*) = "String"
def main() = {
println(foo("ABC")) // Should print "String"
}
}
In Scala 2, this code works fine. When I call foo with a single string argument, both overloads are valid but the String one is more specific, so it gets called. In Scala 3, this is ambiguous.
-- [E051] Reference Error: overloads.scala:9:12 --------------------------------------------------------------------
9 | println(foo("ABC"))
| ^^^
| Ambiguous overload. The overloaded alternatives of method foo in object example with types
| (a: String, args: String*): String
| (a: Any): String
| both match arguments (("ABC" : String))
The equivalent code (two overloads, one of them more specific and having a vararg parameter) also works in Java. What exactly changed in Scala 3 to make this particular call ambiguous? Is this behavior intended? And how can I tell Scala which overload to call in this case?
For what it's worth, I am well aware method overloading is strongly discouraged in Scala. In my actual code, I'm interfacing with a Java builder class that has an overloaded .append method, so I have no control over the function signatures.
This behaviour is mentioned in this PR, in particular in this comment. I don't know if that will be "fixed" or if it's exactly as intended.
Note that the following is not ambiguous:
def foo(s: String)
def foo(a: String, other: String*)
foo("fine!")
With def foo(s: Any), you can explicitly select one overload or the other like this:
foo("fine": Any) // calls foo(Any)
foo("fine", Nil: _*) // calls foo(String, String*) with an empty vararg
PS: I wouldn't say that overloading is "strongly discouraged", but we must be careful and admit that some cases are ambiguous, to the compiler and to humans. It's not obvious to me which definition foo("") should refer to, so it's not completely crazy to be more explicit in that case.
Consider:
trait Validation {
def isValid(str: String): Boolean
}
class AlwaysValid extends Validation {
override def isValid(_: String) = true
}
yields
<console>:1: error: identifier expected but '_' found.
override def isValid(_: String) = true
Any ideas why? Or is that just something the language designers missed?
Maybe it's about named argument passing but this would only apply to non-overrides as overrides auto-"inherit" the argument names from the overridden method anyway, so this can't be it:
trait Foo {
def bar(arg0: String): String
}
class Baz extends Foo {
override def bar(blabla: String) = "hello"
}
new Baz().bar(arg0 = "world") // works, even though the arg name is blabla in Baz
Furthermore: _ is allowed in lambdas, even multiple times:
scala> val x: Int => Int = _ => 3
x: Int => Int = <function1>
scala> val x: (Int, Int) => Int = (_, _) => 3
x: (Int, Int) => Int = <function2>
Because you can use parameters names when calling the method.
Scala allows you to change the name of a parameter when overriding (discouraged though) but you always need to provide a name for the caller to use if they so want.
I think it's simply a grammar issue.
_ is a special identifier in scala, and it's usage is allowed a in a well-defined set of cases, such as lambdas, partial method application and pattern match.
I didn't look into the language spec, but it's safe to assume that a method parameter is expected to be a name identifier and _ is just not a valid one.
Here's a somewhat more detailed explanation of what's going on:
the reason why _ works with lambdas is that lambdas can never have named arguments anyway.
in case of polymorphic calls to subclass (Baz) instances via references of the parent class type (Foo), Scala will simply "inherit" the parent class method names (arg0) into the subclass so polymorphic calls don't see the altered name blabla in Baz#bar;
however, the subclass method still needs to be callable directly as well, so it does need to provide valid names for its arguments, so _ won't work for obvious reasons; it's also recommended that those match the parent class method names which were overridden for reasons of clarity.
In the spec of scala 6.26.2, there are 4 kind of conversions for methods:
MethodConversions
The following four implicit conversions can be applied to methods which are not applied to some argument list.
Evaluation. A parameterless method m of type => T is always converted to type T by evaluating the expression to which m is bound.
Implicit Application. If the method takes only implicit parameters, implicit argu- ments are passed following the rules of §7.2.
Eta Expansion. Otherwise, if the method is not a constructor, and the expected type pt is a function type (Ts′) ⇒ T′, eta-expansion (§6.26.5) is performed on the expression e.
Empty Application. Otherwise, if e has method type ()T , it is implicitly applied to the empty argument list, yielding e().
Some scala code:
def hello(): String = "abc"
def world1(s: String) = s
def world2(s: => String) = s
def world3(s: () => String) = s
world1(hello)
world2(hello)
world3(hello)
My question is, for world1, world2 and world3, which conversion rule is applied to each of them?
def world1(s: String) = s
world1(hello)
Empty application: hello is evaluated as hello() and then passed as the argument of world1
def world2(s: => String) = s
world2(hello)
Eta-expansion + Evaluation: hello is expanded into a function and evaluated lazily.
def world3(s: () => String) = s
world3(hello)
Eta-expansion: hello is expanded to a Function0[String]
Eta-expansion is necessary because methods and functions are two different things, even though the scala compiler is very good at hiding this difference.
The difference comes from the fact that methods are a JVM concept, whereas first-class functions are a scala-specific concept.
You can try this out in a REPL. First, let's define a method hello
scala> def hello(s: String) = s"hello $s"
hello: (s: String)String
scala> hello.hashCode
<console>:9: error: missing arguments for method hello;
follow this method with `_' if you want to treat it as a partially applied function
hello.hashCode
^
Woops, hello is not a value (in the JVM sense)! Not having an hashcode is a proof of it.
Let's get a Function1 out of the hello method
scala> hello _
res10: String => String = <function1>
scala> (hello _).hashCode
res11: Int = 1710358635
A function is a value, so it has an hashcode.
Why does line #2 below compile? It's (seemingly) not giving the required constructor arg.
class F(x: => Unit) {}
new F // Compiles (strange)
def f(x: =>Unit) = ()
f // Does not compile (good)
Is it permitted sugar just for this special case? Can you point to docs on the subject? I'm using Scala 2.9.0.
Scala Reference:
5.1.1 Constructor Invocations
If no explicit arguments are given, an
empty list () is implicitly supplied.
,where () stands for Unit
Why does Jorge Ortiz advise to avoid method overloading?
Overloading makes it a little harder to lift a method to a function:
object A {
def foo(a: Int) = 0
def foo(b: Boolean) = 0
def foo(a: Int, b: Int) = 0
val function = foo _ // fails, must use = foo(_, _) or (a: Int) => foo(a)
}
You cannot selectively import one of a set of overloaded methods.
There is a greater chance that ambiguity will arise when trying to apply implicit views to adapt the arguments to the parameter types:
scala> implicit def S2B(s: String) = !s.isEmpty
S2B: (s: String)Boolean
scala> implicit def S2I(s: String) = s.length
S2I: (s: String)Int
scala> object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") }
<console>:15: error: ambiguous reference to overloaded definition,
both method foo in object test of type (b: Boolean)Int
and method foo in object test of type (a: Int)Int
match argument types (java.lang.String)
object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") }
It can quietly render default parameters unusable:
object test {
def foo(a: Int) = 0;
def foo(a: Int, b: Int = 0) = 1
}
Individually, these reasons don't compel you to completely shun overloading. I feel like I'm missing some bigger problems.
UPDATE
The evidence is stacking up.
It complicates the spec
It can render implicits unsuitable for use in view bounds.
It limits you to introduce defaults for parameters on only one of the overloaded alternatives.
Because the arguments will be typed without an expected type, you can't pass anonymous function literals like '_.foo' as arguments to overloaded methods.
UPDATE 2
You can't (currently) use overloaded methods in package objects.
Applicability errors are harder to diagnose for callers of your API.
UPDATE 3
static overload resolution can rob an API of all type safety:
scala> object O { def apply[T](ts: T*) = (); def apply(f: (String => Int)) = () }
defined object O
scala> O((i: String) => f(i)) // oops, I meant to call the second overload but someone changed the return type of `f` when I wasn't looking...
The reasons that Gilad and Jason (retronym) give are all very good reasons to avoid overloading if possible. Gilad's reasons focus on why overloading is problematic in general, whereas Jason's reasons focus on why it's problematic in the context of other Scala features.
To Jason's list, I would add that overloading interacts poorly with type inference. Consider:
val x = ...
foo(x)
A change in the inferred type of x could alter which foo method gets called. The value of x need not change, just the inferred type of x, which could happen for all sorts of reasons.
For all of the reasons given (and a few more I'm sure I'm forgetting), I think method overloading should be used as sparingly as possible.
I think the advice is not meant for scala especially, but for OO in general (so far I know scala is supposed to be a best-of-breed between OO and functional).
Overriding is fine, it's the heart of polymorphism and is central to OO design.
Overloading on the other hand is more problematic. With method overloading it's hard to discern which method will be really invoked and it's indeed a frequently a source of confusion. There is also rarely a justification why overloading is really necessary. The problem can most of the time be solved another way and I agree that overloading is a smell.
Here is an article that explain nicely what I mean with "overloading is a source of confusion", which I think is the prime reason why it's discouraged. It's for java but I think it applies to scala as well.