Reputation: 1034
What is the proper way to explicitly return the Unit
type from a method, using ()
or Unit
? It appears to me that both work in all cases I've tried myself.
For context, this often occurs if I'm writing a method with side effects and returns Unit
that calls another method, which also performs side effects but returns some value instead of Unit
. e.g.
def effectAndReturn(): String = {
val msg = "Hello, SO"
println(msg)
msg
}
def doEffect(): Unit = {
val _ = effectAndReturn()
() // `Unit` also works here
}
From my understanding ()
is the only value of type Unit
that exists. Returning the token Unit
in doEffect()
is referencing the Unit
companion object; I'm confused how this would return a value as there's not even an apply
method defined on it. Returning the companion object for a given abstract class's type isn't valid as a return value as far as I know.
Plugging these into a Scala REPL is also interesting
scala> val parenUnit = ()
parenUnit: Unit = ()
scala> parenUnit
// Returns blank line
scala> val wordUnit = Unit
wordUnit: Unit.type = object scala.Unit
scala> wordUnit
res1: Unit.type = object scala.Unit
scala> res1
res2: Unit.type = object scala.Unit
()
is simply a Unit
value, whereas Unit
gives back a type, which doesn't make sense to me as no other companion objects do this as far as I can tell. My guess is that the compiler handles Unit
in a particular and unique way compared to any other type, but how exactly?
Upvotes: 9
Views: 10424
Reputation: 1572
Suppose we have two methods in a class called TestUnit
:
class TestUnit {
def foo(): Unit = 2217
def bar(): Int = 1478
}
Let's look at its bytecode:
// access flags 0x1
public foo()V
L0
LINENUMBER 4 L0
SIPUSH 2217
POP
RETURN // returns void
L1
LOCALVARIABLE this Lunit/TestUnit; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x1
public bar()I
L0
LINENUMBER 5 L0
SIPUSH 1478
IRETURN // returns integer because it is declared in method
L1
LOCALVARIABLE this Lunit/TestUnit; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
My assumption is - the Scala compiler just put RETURN
instruction (which returns void) in every method where Unit
is declared as returning type. (you can look listings here)
So you can return any type in doEffect()
. But as @ghik said, it's better to use ()
.
Upvotes: 1
Reputation: 10764
So, we have:
Unit
type()
which is of type Unit
Unit
companion object which causes the confusion. It is not of type Unit
. It is of type Unit.type
(its own singleton type). However... Scala automatically implicitly converts everything to Unit
and that's why you can use it where Unit
type is expected.TLDR: Use ()
Upvotes: 20