1

I'm very new to Scala, and tried to write a simple Scala program that gets the maximum value. I found something weird (probably a language-specific feature). Here it is:

  def max(xs: List[Int]): Int = {
    if (xs.isEmpty) {
      throw new java.util.NoSuchElementException
    }

    def maxAux(x: List[Int], curMax: Int): Int = {
      if (x.isEmpty)  {
        curMax
      }
      if (x.head > curMax) {
        maxAux(x.tail, x.head)
      }
      else {
        maxAux(x.tail, curMax)
      }
    }
    maxAux(xs.tail, xs.head)
  }
}

For some reason, inside of maxAux function, the return of the first if statement gives me an IntelliJ warning that it is an "unused expression". Turns out it is correct because that line doesn't seem to return. To get around that issue, the second if statement in maxAux I changed to an else if, and then everything worked as intended. The other fix would be to add a return statement before curMax, but apparently using return is bad style/practice.

TL;DR: Can anyone explain why in the code above curMax doesn't return?

2 Answers 2

3

The immediate problem is that Scala returns the value of the last expression in a block which is the second if/else expression. So the value of the first if is just discarded. This can be fixed by making the second if an else if so that it is a single expression.

A better solution is to use match, which is the standard way of unpicking a List:

def maxAux(x: List[Int], curMax: Int): Int =
  x match {
    case Nil =>
      curMax
    case max :: tail if max > curMax =>
      maxAux(tail, max)
    case _ :: tail =>
      maxAux(tail, curMax)
  }
Sign up to request clarification or add additional context in comments.

Comments

1

In def maxAux, the control-flow can enter the first if-branch, whose body yields curMax. But that if-statement is not the last statement in maxAux, another if- or else-branch will follow, and they determine the result.

If you test your function (note that your code currently doesn't compile!), e.g. via println(max(List(1,3,2,5,0))), then you'll get a NoSuchElementException, which is a consequence of your current (incorrect) implementation.

You have various options now, e.g. the following two, which only minimally change your code:

  1. Fix the if-else cascade (which you could also rewrite into a pattern matching block):

    if (x.isEmpty)  {
      curMax
    } else if (x.head > curMax) {
      maxAux(x.tail, x.head)
    } else {
     maxAux(x.tail, curMax)
    }
    
  2. Use a return statement (though you should be careful with the use of return in Scala. See the comments under this answer):

    if (x.isEmpty)  {
      return curMax
    }
    

8 Comments

Please don't use return unless you know what it does, which is probably not what you think it does.
If you don't know what return does, see this or this
@Tim See github.com/databricks/scala-style-guide#return for when to prefer return statements: it matches this case exactly. The Scala compiler & SDK also use return statements in such cases. If you don't know when to use return, maybe don't rush to comments so hastily.
That is one style guide for one platform. By contrast, the online course given by the author of the language deducts style points for using return, which is good enough for me. Also, you might want to actually use return in your answer.
Thanks for the updated answer, it is good now. The problem with return is that it may have hidden consequences and can usually be replaced by a more "pure" functional coding style. The libraries use a lot of non-functional features (e.g. mutable data, while loops) in order to improve efficiency. (Which is, of course, an indictment of the ability of Scala to implement functional code in an efficient way, though this is often the fault of the JVM rather than Scala itself).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.