Why Unit is a supertype of anything else? - scala

Here's an example:
$ scala
Welcome to Scala 2.11.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_112).
Type in expressions for evaluation. Or try :help.
scala> val a: Unit = 1
<console>:11: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
val a: Unit = 1
^
a: Unit = ()
In Scala documentation:
There is only one value of type Unit, ()
Why is Scala compiler silently coercing values to Unit?
A bit of context: I used Future[Unit] type to describe some procedure which does not return anything. And since Future[Unit] is now effectively a subtype of Unit, I got bit by some funny bugs (someFuture.map(a => Future(a)) silently skips calling the operation instead of giving compilation warning). What am I supposed to use as a type of operation that does not return any meaningful result?

Unit is not a supertype of other types. What happens instead is called value discarding: when the expected type of an expression e is Unit, the compiler replaces it by {e; ()}. This is done to make some behavior more familiar. E.g.
val sb = new StringBuilder
val strings: List[String] = ...
for (str <- strings) { sb.append(str) }
By analogy with for loops in other languages, we would expect it to compile. But without value discarding it wouldn't: this is equivalent to strings.foreach(str => sb.append(str)), the type of str => sb.append(str) is String => StringBuilder (because all append methods on StringBuilder return the builder itself) and foreach on List[String] takes String => Unit.
You can add -Ywarn-value-discard compiler option to warn you when it happens (and write for (sb <- sbOpt) { sb.append("a"); () } explicitly).
Or you can actually go with a trick of defining your own Unit (possibly changing the name to avoid confusion for anyone reading your code):
object Unit
type Unit = Unit.type
implicit def unit2scalaunit(a: Unit): scala.Unit = ()
implicit def scalaunit2unit(a: scala.Unit): Unit = Unit
This should avoid running into the problem with Future you describe.

Unit is not a supertype of everything! Scala actually has a pretty wide variety of conversions that happen automatically and this is one of them. From section 6.26.1 Value Conversions of the Scala language spec, one of the conversions is
Value Discarding
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; () }.
So when you write something like val a: Unit = 1, it gets processed into val a: Unit = { 1; () }, which is quite different. The warning is actually very helpful here - it is warning you that you probably did something wrong: the expression you are trying to put into statement position is pure (has no side-effects), so executing it has no effect (except possibly to cause the program to diverge) on the final output.

Related

What is the Unit Type Behavior in Scala

Why does this code works:
val f: String => Unit = {(_:String) => 2}
//or more succinctly
val f: String => Unit = _ => 2
Clearly the body of my function return an int. However the type expected is Unit
But if i do
implicitly[String <:< Unit]
//Cannot prove that String <:< Unit.
Hence i am a bit confused as to how the cast is happening ? Why is it even allowed in the first place
This is called Value Discarding, see 6.26.1 Value Conversions, sub-section Value Discarding of the Scala Language Specification:
If 𝑒 has some value type and the expected type is Unit, 𝑒 is converted to the expected type by embedding it in the term { 𝑒; () }.
In other words, your code is compiled as-if you had written
val f: String => Unit = {(_:String) => { 2; () }}
//or more succinctly
val f: String => Unit = _ => { 2; () }
I guess the intention behind this feature is familiarity for programmers coming from imperative programming languages, where it is often possible to discard values.
E.g. in C, it is legal to write
printf("Hello");
and discard the return value, even though printf returns an int. This goes together with the idea of expression statements and statement expressions that many imperative programming languages have.
In Scala any type A can be transformed into type Unit. It's not subtyping, it's transforming. Like type A means some possible side effect plus returning A while Unit means we disregard return value but keep the side effect.

What is the return type of a scala if statement without else

I made a mistake similar to the following in some Scala code:
val someVal:String = if (someX == someY) n
In retrospect the mistake is clear to me (it has to assign something to someVal, and if the expression is false, it's probably not going to be a string). I want to know what the value returned would be if the expression is false. My best guess is Unit, or perhaps AnyVal.
That code will not compile, because for someVal to be a String, then each execution path (the if and the else) would have to return a String. However since you don't have an else, this is impossible and thus won't compile.
The compiler error will be the following, which is indicating that you are returning a Unit when you are supposed to return String:
error: type mismatch;
found : Unit
required: String
That's because what you have is equivalent to this:
val someVal: String = if (foo == bar) "Hello World" else ()
() is the only value of Unit, which is not a valid value for a String type.
In the future you can use the Scala repl and have it tell you the types (just don't specify one):
scala> val someVal1 = if (true) "Hello World"
someVal1: Any = Hello World
val someVal2 = if (false) "Hello World"
someVal2: Any = ()
As you can see the type is Any because that is the only common parent between Unit and String:
The type of whole if expression will be the smallest common supertype of all branches.
The true path is String in your example
A missing else is the same as an empty else, both evaluate to Unit.
Unit and String are in completely separate inheritance trees, (String is AnyRef and Unit is AnyVal) so the type of the whole expression is Any, the common super type of all types in Scala.
If the true case resulted in an AnyVal type (for example, Int) then the type of the whole expression would be AnyVal
If the true case evaluated to Unit (for example if you just used println in the if instead of returning a value) then the type of the expression would be Unit which makes sense since both paths have the same type.

Assign Future[Unit] to Unit

Why does this compile
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> val f: Unit = Future.successful(())
f: Unit = ()
I expected the compiler to complain about the assignment.
This is called "Value Discarding". Citing the scala specification (6.26.1):
Value Discarding
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; () }.
In other words, any value, whatever its type, is implicitly converted to Unit, effectively discarding it.
It you want to be warned about such discarding (which can in some cases hide a bug), you can pass the -Ywarn-value-discard option to the compiler. You'll then have to explicitly return () every time you call a method only for its side effect, but that method does return a non-Unit value.
The compiler is fine since applying f will only execute the call
val f: Unit = Future.successful(())
and the return value will go into the nirvana.
Basically this is the same as:
val f: Unit = {
Future.successful(())
()
}
If the compiler don't find the Unit it expects in the last value of the method it will put it there.

Reify a ValDef from compile to runtime

I want to reify a ValDef into runtime, but i does not work directly. If i encapsulate the ValDef into a Block, everything works perfectly, like in the following example:
case class Container(expr: Expr[Any])
def lift(expr: Any): Container = macro reifyValDef
def reifyValDef(c: Context)(expr: c.Expr[Any]): c.Expr[Container] = {
import c.universe._
expr.tree match {
case Block(List(v: ValDef), _) =>
val asBlock = q"{$v}"
val toRuntime = q"scala.reflect.runtime.universe.reify($asBlock)"
c.Expr[Container](q"Container($toRuntime)")
}
}
lift {
val x: Int = 10
}
If i would use v directly, instead of wrapping it into a block, I get the error:
Error:(10, 11) type mismatch;
found :
required: Any
Note that extends Any, not AnyRef.
Such types can participate in value classes, but instances
cannot appear in singleton types or in reference comparisons.
val x: Int = 10
^
Is it just not working directly with ValDefs or is something wrong with my code?
That's one of the known issues in the reflection API. Definitions are technically not expressions, so you can't e.g. pass them directly as arguments to functions. Wrapping the definition in a block is a correct way of addressing the block.
The error message is of course confusing, but it does make some twisted sense. To signify the fact that a definition by itself doesn't have a type, the tpe field of the corresponding Tree is set to NoType. Then the type of the argument of a macro is checked against Any and the check fails (because NoType is a special type, which isn't compatible with anything), so a standard error message is printed. The awkward printout is an artifact of how the prettyprinter behaves in this weird situation.

What's the difference between using and no using a "=" in Scala defs ?

What the difference between the two defs below
def someFun(x:String) { x.length }
AND
def someFun(x:String) = { x.length }
As others already pointed out, the former is a syntactic shortcut for
def someFun(x:String): Unit = { x.length }
Meaning that the value of x.length is discarded and the function returns Unit (or () if you prefer) instead.
I'd like to stress out that this is deprecated since Oct 29, 2013 (https://github.com/scala/scala/pull/3076/), but the warning only shows up if you compile with the -Xfuture flag.
scala -Xfuture -deprecation
scala> def foo {}
<console>:1: warning: Procedure syntax is deprecated. Convert procedure `foo` to method by adding `: Unit =`.
def foo {}
foo: Unit
So you should never use the so-called procedure syntax.
Martin Odersky itself pointed this out in his Scala Day 2013 Keynote and it has been discussed in the scala mailing list.
The syntax is very inconsistent and it's very common for a beginner to hit this issue when learning the language. For this reasons it's very like that it will be removed from the language at some point.
Without the equals it is implicitly typed to return Unit (or "void"): the result of the body is fixed - not inferred - and any would-be return value is discarded.
That is, def someFun(x:String) { x.length } is equivalent to def someFun(x:String): Unit = { x.length }, neither of which are very useful here because the function causes no side-effects and returns no value.
The "equals form" without the explicit Unit (or other type) has the return type inferred; in this case that would be def someFun(x:String): Int = { x.length } which is more useful, albeit not very exciting.
I prefer to specify the return type for all exposed members, which helps to ensure API/contract stability and arguably adds clarity. For "void" methods this is trivial done by using the Procedure form, without the equals, although it is a stylistic debate of which is better - opponents might argue that having the different forms leads to needless questions about such ;-)
The former is
def someFun(x: String): Unit = {
x.length
() // return unit
}
And the latter is
def someFun(x: String): Int = {
x.length // returned
}
Note that the Scala Style guide always recommend using '=', both in
method declaration
Methods should be declared according to the following pattern:
def foo(bar: Baz): Bin = expr
function declaration
Function types should be declared with a space between the parameter type, the arrow and the return type:
def foo(f: Int => String) = ...
def bar(f: (Boolean, Double) => List[String]) = ...
As per Scala-2.10, using equals sign is preferred. Infact you must use equals sign in call declarations except the definitions returning Unit.
As such there is no difference but the first one is not recommended anymore and it should not be used.