object A extends App {
def closure1(x:Int) = {
object O {
def getX = x
def add(y:Int) = x+y
}
val foo = O
foo
}
def closure2(x:Int) {
object O {
def getX = x
def add(y:Int) = x+y
}
val foo = O
foo
}
println(closure1(4).getClass)
println(closure2(4).getClass)
}
result:
$scala A
class A$O$3$
void
Scala has a shorthand notation for code that doesn't return any interesting value: omit the =
sign. In Java, this would return void
, i.e. nothing at all; but in Scala it's actually ()
, the only member of the type called Unit
. Either way, it's the same: nothing or a meaningless placeholder.
The reason you want a meaningless placeholder is that when you write generic code you'd rather not have to handle the cases of something vs. nothing differently.
Anyway:
def f(): Unit = println("Hi")
is a function that explicitly returns only the content-free ()
value (which is what println
returns also). And the shorthand is
def f() { println("Hi") }
Now there's one sneaky addition which is that in Scala, as with many C-derived languages, you're allowed to just throw away the return value from whatever you do. And when you throw it away, all that's left is ()
. Scala will warn you on closure2
that you are doing something suspicious:
<console>:16: warning: a pure expression does nothing in statement position
you may be omitting necessary parentheses
foo
^
defined module A
but will still let you do it (as it is historically expected that this will work).
So, to summarize:
def f {}
is a method that returns only the content-free placeholder ()
. If you write it out in full the syntax would be
def f: Unit = {}
and when you try to return a value of the wrong type, instead of complaining it throws away the value and gives you type Unit
, but typically emits a warning:
def f: Unit = 5
def f { 5 }
(Note that opinion is mostly against the short form these days (these days being 2.10-is-stable), in large part because in the absence of a clear explanation of the difference, new users often omit =
without realizing it and then wonder why things don't work. So in the future (2.11 or 2.12 for deprecation?) the def f {}
form may not work.)
If you actually want a return value--because, for example, you want to return your object O
(which you can do directly without first assigning it to foo
, by the way), make sure you include =
:
def f = { object O { def g = 5 }; O }
scala> f.g
res0: Int = 5
(Hint: the compiler will complain at you that you're using structural types here. You're better of with trait HasG { def g: Int }
and then object O extends HasG
; otherwise Scala actually uses reflection to call f.g
for some rationale that I've never quite been able to follow.)
I think Rex has explained the reason, you omitted the =
when define closure2
, which make Scala compiler think you'd like to return nothing, even though you intend to return foo
.
scala> def closure3(x: Int) {
| object O {
| def getX = x
| def add(y: Int) = x + y
| }
| val foo = O
| foo
| }
<console>:17: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
foo
^
closure3: (x: Int)Unit
Note the return type of closure3
is Unit
scala> def closure4(x: Int) = {
| object O {
| def getX = x
| def add(y: Int) = x + y
| }
| O
| }
closure4: (x: Int)Object{def getX: Int; def add(y: Int): Int}
scala> closure3(2)
closure3(2)
return nothing, so you can not call getX
scala> closure4(2)
res10: Object{def getX: Int; def add(y: Int): Int} = O$2$@a4920bc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With