1

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?

1 Answer 1

7

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) } 
Sign up to request clarification or add additional context in comments.

4 Comments

procedure syntax is deprecated under -Xfuture. I guess this is why.
Thank you, you clarified even more things than I realized were confusing me! If I may ask a follow up question, can you explain what is returned when an exception is thrown? Specifically, I originally wanted to put lines 2 and 3 together as part of a guard clause instead of an if-else conditional but this causes another instance of type mismatch (Unit instead of Int) and then the compiler proceeds to say "xs" has no value when used in the call to the findMax function.
throws is a very special case. It does not return. Neither do trys that don't catch the type of exception thrown. In this case, the return type of throws or try is a special bottom type called Nothing. There are no instances of Nothing--not even null is Nothing. Nothing is a subtype of everything, so an if that returns Nothing in one branch and an Int in the other ultimately returns Int because that's the lowest common type of its two branches.
If I understand correctly, you had an if with no else? That's not really wrong. Your type error was probably because findMax was returning Unit but max was supposed to return an Int.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.