Ryan B
Ryan B

Reputation: 166

Scala Type Mismatch Unit Instead of Int

Complete beginner to Scala and just trying to figure out the basics right now.

As part of a tutorial I'm trying to create a function that returns the largest element in a list of integers. To accomplish this I've (tentatively) put together a the following code:

def max(xs: List[Int]): Int =
  if (xs.isEmpty)
    throw new java.util.NoSuchElementException
  else
    findMax(xs.head, xs.tail)

def findMax(a: Int, b: List[Int]) {
  if (b.isEmpty) return a

  if (a > b.head)
    findMax(a, b.tail)
  else
    findMax(b.head, b.tail)
}

However, when I try to compile it I get a type error for line 5.

[error]  /scala/example/src/main/scala/example/Lists.scala:5: type mismatch;
[error]  found   : Unit
[error]  required: Int
[error]         findMax(xs.head, xs.tail)

I have to admit I'm a bit confused by this error message as I don't understand how the compiler thinks I'm trying to pass in a Unit type given the logic to ensure a List is not empty prior to this line.

Can anyone help to clarify the issue here?

Upvotes: 1

Views: 1530

Answers (1)

Zeimyth
Zeimyth

Reputation: 1395

Scala has two constructs for defining a function:

def doSomething(a: Int) { a + 3 }

and

def doSomethingElse(b: Int) = { b + 3 }

The first one is known as procedure syntax, and it is discouraged because it leads to poor assumptions and confusing code. The difference between these two functions is that doSomething returns Unit, whereas doSomethingElse returns Int. If you do not include an =, your function will not return anything (in other words, it returns Unit).

This

def doSomething(a: Int) { a + 3 }

is equivalent to

def doSomething(a: Int): Unit = { a + 3 }

You want your function findMax to return an Int, but because you left off the =, Scala says it returns Unit. This is the cause of your compile error. You can fix this by either writing

def findMax(a: Int, b: List[Int]) = {

or

def findMax(a: Int, b: List[Int]): Int = {

In general, you should never use procedure syntax. Always use =, even if you ultimately leave the final return type up to type inference.


It should be noted that the first approach might actually result in a compiler error because you used return in your function. Functions that explicitly call return are required to specify the type that they return in the function header. Because Scala is an expression-based language, every statement is an expression and thus returns a value. You can rewrite your findMax function to not need return as follows:

def findMax(a: Int, b: List[Int]): Int = {
  if (b.isEmpty)
    a
  else if (a > b.head)
    findMax(a, b.tail)
  else
    findMax(b.head, b.tail)
}

Upvotes: 7

Related Questions