Question

I'm intrigued by the following Scala compiler behavior. When i declare a function of type unit, but nevertheless provide as body a function that evaluate to an Int, the Scala compiler is ok with it.

def add(x:Int, y:Int) = x + y
def main(args: Array[String]): Unit = {add(args(0).toInt, args(0).toInt)}

While the same is not true with other type such in

def afunc: String = {1} //type mismatch;  found   : Int(1)  required: String

Also if i write

def afunc: Unit = {1}

or

def main(args: Array[String]): Unit = {2 + 2} // Which is just like the first addition above

In both case i get the following warning:

a pure expression does nothing in statement position; you may be omitting necessary parentheses 

In a sense there is 2 questions here. What is the difference between a function that return evaluate to an Int and the expression 2 + 2. Then why on earth, the compiler does not complain that a function that is suppose to evaluate to Unit, gets a body that evaluate to another type, as it would happens between other types.

Many thanks in advance,

Maatari

Was it helpful?

Solution

What is the difference between a function that return evaluate to an Int and the expression 2 + 2.

A function that evaluates to an Int might have side effects

var a = 0
def fn: Int = {
  a = a + 1
  1
}

Every call to fn changes the value of a.

Then why on earth, the compiler does not complain that a function that is suppose to evaluate to Unit, gets a body that evaluate to another type, as it would happens between other types.

When you specify Unit as the return type the compiler does an implicit conversion from whatever value the function returns to Unit (there is only one Unit value as it is an object, you can think of it as the void type of Scala).

OTHER TIPS

Unit is inferred as a return type for convenience. For example,

scala> val h = new collection.mutable.HashMap[String,String]
h: scala.collection.mutable.HashMap[String,String] = Map()

scala> h += "fish" -> "salmon"
res1: h.type = Map(fish -> salmon)

we see that the += method on mutable HashMaps returns the map.

But if you don't infer unit, then

def add(a: String, b: String): Unit = h += a -> b

doesn't work.

Which thing is worse--accidentally expecting a return value vs. demanding you explicitly return the most boring possible return value--depends on how functional your code is. If you have more than a few side-effects, not inferring Unit is rather painful.

A function with just the parentheses is mainly called for the side-effects. It may return a result, as it was common in the days of C or Java but in reality we don't care, cause we will not use it. {} is equivalent to : Unit =, and the annotation of return type can be seen as a cast or an implicit conversion to match the type expected by the function.

Here is another example where this behavior occurs.

def add(a: Int, b:Int) : Double = a + b
add: (a: Int, b: Int)Double

scala> add(4,5)
res17: Double = 9.0

Thus it seems that every value can be transformed to unit.

scala> val a: Unit = 1:Unit
<console>:28: warning: a pure expression does nothing in statement position; you may be omitting    necessary parentheses
   val a: Unit = 1:Unit
                 ^
a: Unit = ()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top