There’s never a good reason to use the
return
keyword.
There’s an argument to be made that the more ways there are to reach a given line of code, the harder that code is to reason about.
See GOTO statements considered harmful for an eloquent dissertation on the matter.
If return
were referentially transparent, you should be able to inline expressions that use it and not change the meaning of a program.
Here’s foo1
, a method whose return values are pre-computed and stored in values:
def foo1(i: Int): Int = {
val pos = return i
val neg = return -i
if(i > 0) pos
else neg
}
And foo2
, the same method but with the return values inlined:
def foo2(i: Int): Int = {
if(i > 0) return i
else return -i
}
If return
was referentially transparent, we’d get the same foo1
and foo2
output for the same input, but:
foo1(-1)
// res0: Int = -1
foo2(-1)
// res1: Int = 1
Let’s take the following, fairly straightforward method:
def foo(is: List[Int]): List[Int] = is.map(n => return n + 1)
// error: type mismatch;
// found : Int
// required: List[Int]
// def foo(is: List[Int]): List[Int] = is.map(n => return n + 1)
// ^^^^^
The compilation error doesn’t seem to make much sense - how can a map
on a List[Int]
yield an Int
? But the compiler tends to be smarter than us about these things, so let’s play along.
def foo(is: List[Int]): Int = is.map(n => return n + 1)
// error: type mismatch;
// found : List[Nothing]
// required: Int
// def foo(is: List[Int]): List[Int] = is.map(n => return n + 1)
// ^
It’s unclear how Nothing
got mixed up in there, and is usually the sign that something went south, but fine, down the rabbit hole we go:
def foo(is: List[Int]): List[Nothing] = is.map(n => return n + 1)
// error: type mismatch;
// found : Int
// required: List[Nothing]
// def foo(is: List[Int]): List[Int] = is.map(n => return n + 1)
// ^^^^^
(╯°□°)╯︵ ┻━┻
I don’t understand what’s going on there, nor do I really want to. return
is mad. Don’t use it.
Linter | Rule |
---|---|
Scalastyle | |
Scapegoat |
|
WartRemover |