Corey Wu
Corey Wu

Reputation: 1159

Scala type mismatch in function which returns Double => String when "return" keyword is used

I have a function which returns a Double => String function in Scala. When I add the returns at the end of the function, I get a type mismatch:

type mismatch; found : String required: Double ⇒ String

Why is this the case? Isn't return purely optional in Scala? In this scenario, everything is fine when I delete the two returns, but what would I do if I wanted to return somewhere before that if/else?

def createBuckets(start: Double, end: Double, gap: Double): Double => String = {
  var buckets: List[String] = List[String]()
  val endPoints: List[Double] = List[Double]()

  var first = start
  var second = gap
  while (second < end) {
    buckets ::= first + " to " + second 
    first = second
    second += gap
  }
  if (first != end) {
    buckets ::= first + " to " + end 
  }
  buckets = buckets.reverse
  println("BUCKETS: " + buckets)

  val range = end - start

  (input: Double) => {
    val bucket = (input / gap).floor.toInt
    if (input == end) {
      // Type mismatch from this return
      return buckets(buckets.size - 1)
    } else {
      // and this one
      return buckets(bucket)
    }
  } 
}

Upvotes: 0

Views: 1368

Answers (4)

Ben Reich
Ben Reich

Reputation: 16324

Here is a simplified version of your error:

 def foo: Int => Int = { x => return x } //error

Note that return is only used in methods definitions. It is not usually valid in anonymous functions. This syntactic error is clearer if you try declaring a val instead:

val foo: Int => Int = { x => return x }
//error: return outside method definition

You can read more about the difference between methods and functions here.

Even in method bodies, return is almost always unidiomatic in Scala, and is generally avoided. If you want to return before the final if-else, you can wrap the whole block in another if-else, or instantiate a val and make the last statement of the expression the val (e.g. { val x = 5; ...; x }).

Upvotes: 3

som-snytt
som-snytt

Reputation: 39577

If for some reason a return was called for:

def outer(): Int => String = {
  def f(i: Int): String = { if (i < 0) return "BAD" ; "hello" take i }
  f
}

Your only hangup is that you want to return a function with minimal boilerplate.

This is just a compiler bug, but it's pretty funny:

object X { def f(i: Int = return 42) = i * 2 }

Upvotes: 3

triggerNZ
triggerNZ

Reputation: 4761

return returns from your def, not your anonymous function. Hence the type error. Now, as stated in other answers, in your case you could simply remove it:

if (input == end) {
  buckets(buckets.size - 1)
} else {
  // and this one
  buckets(bucket)
}

You don't need early return statements, and in general you can structure any code to have a single return point.

For example a common pattern in imperative languages:

def sillyExample(input) {
  if (input.isBad) {
    return None
  } 

  //some complex operations go here
  return Some(complexResult);
}

This can be rewritten as:

def sillyExample(input) {
  if (input.isBad) {
    None
  } else {
   //some complex operations go here
   Some(complexResult);
  }
}

That is no more complex. The extra level of indentation for the happy-path code can be annoying (and can be solved by higher functional abstractions but I digress), but you get used to it very quickly. The advantage on not having arbitrary return statements, and focusing on expressions instead is that it brings you a step closer to referential transparency

Upvotes: 2

Andrei Heidelbacher
Andrei Heidelbacher

Reputation: 125

You should remove the return keywords because they forcefully return a result from the createBuckets function and you get a type mismatch error because the returned type is a String (the bucket), not a function from Double to String. Using the return keyword is not idiomatic scala and you should try to avoid it. I hope this helps.

Upvotes: 1

Related Questions