Reputation: 47041
The codes are below:
scala> def f(x:Int => Unit):Unit = 1
<console>:7: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
def f(x:Int => Unit):Unit = 1
^
f: (x: Int => Unit)Unit
scala> f(_=>2);
<console>:9: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
f(_=>2);
^
scala> f(_=>List(1,2));
All three expressions above worked in REPL(with some warnings), but they look a bit confusing..
In the first expression, f
's return type is Unit
, which is the subtype of AnyVal
but not the Supertype of Int
, therefore, I can't understand why 1
can be used as the returned value.
In the second expression, _=>2
also used 2
instead of Unit
as the returned value, which conflicts with the definition.
In the third expression, _=> List(1,2)
even uses List
, subtype of AnyRef
as the returned value, but the REPL still doesn't complain about this..
Does anyone have ideas about why Unit
can tolerate the non-subtype type conversion here? Thanks!
Upvotes: 4
Views: 759
Reputation: 5919
In addition to the answer of Ben Reich:
Conceptually, in Scala the type Unit
is the super type of every other type. Therefore, every value, including Int
, is assignable to Unit
. Effectively, if used as a return type of a method, the compiler will throw away the result value, giving the method the JVM/Java void
type.
Nothing
is the exact opposite, by the way: Conceptually, it is a subtype of every other type. Since no instance of Nothing
exists, no instance of any other type can therefore be assignment compatible with Nothing
.
Java's void
somehow is an incomplete mix of both of those.
Upvotes: -1
Reputation: 16324
Scala will automatically insert ()
(the singleton Unit
value) in this case to make the typechecking work. So what you have is equivalent to:
def f(x:Int => Unit):Unit = { 1; () }
This is known as "value discarding" in Scala. From the spec:
Value Discarding
If
e
has some value type and the expected type isUnit
,e
is converted to the expected type by embedding it in the term{ e; () }
Like in many programming languages, this is meant to facilitate just "throwing out" the return value of the expression. This allows you to make a method of type Unit
that only uses the side effects of an expression.
Upvotes: 14
Reputation: 3486
Check implicit conversions section in SLS
ValueDiscarding. If e has some value type and the expected type is Unit, e is converted to the expected type by embedding it in the term {e; () }.
Upvotes: 2