why is the use of return a bad habit in scala

2020-04-21 08:24发布

问题:

I am doing scala through the functional programming course on coursera. I noticed that the automatic style checker tells me that the use of 'return' is a bad habit. Why is that? To me it seems like the use of return would make the code more readable because any other programmers can instantly see that and what the function is returning.

Example, why is this;

def sum(xs: List[Int]): Int = {
    if( xs.length == 0){
      return 0
    }else{
      return xs.head + sum(xs.tail)
    }
}

Considered to be worse than this;

def sum(xs: List[Int]): Int = {
    if( xs.length == 0){
      0
    }else{
      xs.head + sum(xs.tail)
    }
}

I am used to javascript, so that might be a reason why I feel uneasy about it. Still, can anybody make it obvious why the addition of the return statement makes my code worse? If so, why is there a return statement in the language?

回答1:

In Java, Javascript and other imperative languages if...else is a flow-control statement.

This means you can do this

public int doStuff(final boolean flag) {
    if(flag)
        return 1;
    else
        return 5;
}

But you cannot do this

public int doStuff(final boolean flag) {
    return if(flag)
        1;
    else
        5;
}

Because if...else is a statement and not an expression. To accomplish this you need to use the ternary operator (strictly speaking the "conditional operator"), something like:

public int doStuff(final boolean flag) {
    return flag ? 1 : 5;
}

In Scala, this is different. The if...else construct is an expression, so more akin to the conditional operator in the languages you are used to. So, in fact your code is better written as:

def sum(xs: List[Int]): Int = {
    return if(xs.length == 0) {
      0
    } else {
      xs.head + sum(xs.tail)
    }
}

Further, the last expression in a function is automatically returned, so the return is redundant. In fact, as the code only has single expressions, the curly brackets are redundant too:

def sum(xs: List[Int]): Int = 
    if(xs.length == 0) 0
    else xs.head + sum(xs.tail)

So, to answer your question: this is discouraged because it is a misinterpretation of the nature if the if...else construct in Scala.

But this is all a little besides the point, you should really be using pattern matching

def sum(xs: List[Int]): Int = xs match {
   case Nil => 0
   case head::tail => head + sum(tail)
}

This is much more idiomatic Scala. Learn how to use (and abuse) pattern matching and you will save yourself a huge number of lines of code.



回答2:

I think another answer for the question why

why is the use of return a bad habit in scala

is that return when used in a closure will return from the method not from the closure itself.

For example, consider this code:

def sumElements(xs: List[Int]): Int = { 
  val ys: List[Int] = xs.map { x => 
    return x + 1
  }
  return ys.sum 
}

It can be easily missed that when this code is invoked with sumElements(List(1, 2, 3, 4)) the result will be 2 and not 10. This is because return within map will return from sumElements and not from the map call.



回答3:

In scala, every line is an expression, not a statement. Statements generally don't have a return value, but expressions do.

The last result of a block will be the returned value, and so the style guide operates on this assumption. A return would be an exceptional exit from a block.

def sum(xs: List[Int]): Int = { if(xs.isEmpty) return 0 xs.head + sum(xs.tail) }

The return statement there would cause the function to bail at that return, and generally leads to less understandable code than if you wrote it with the if/else logic, as you did earlier. I believe the rational behind the style decision is to discourage this type of programming as it makes the programs more difficult to understand.