12

I was reading the description of the Scala WartRemover tool, and was confused by one of the points they had. The description said this:

return breaks referential transparency. Refactor to terminate computations in a safe way.

// Won't compile: return is disabled
def foo(n:Int): Int = return n + 1
def foo(ns: List[Int]): Any = ns.map(n => return n + 1)

This doesn't make any sense to me, and both of the examples look referentially transparent. Is there some way in which the return keyword makes it any more likely for a function to break referential transparency? Am I just completely misunderstanding their point?

resueman
  • 10,572
  • 10
  • 31
  • 45
  • I think the `return` warning is meant to prevent uses such as `def f(x : Int):Int = ((w : Nothing) => 3) (return x)` (which is the identity function, not the constant `3`). While I can agree with banning `return` (is there any reason for using it at all in pure code?), I wouldn't say that an "early return" breaks referential transparency, since you could achieve the same effect exploiting a continuation-passing transform. – chi Jan 06 '15 at 14:24
  • 1
    @chi, call/cc or similar constructs that allow you to get a first-class handle on your _implicit_ continuation are not referentially transparent either. Being passed a continuation function _explicitly_ is an entirely different story. That a global transformation creates a referentially transparent program does not imply that the original is referentially transparent (otherwise mutable state would be RT as well). – Andreas Rossberg Jan 06 '15 at 14:49
  • @AndreasRossberg I see. I was probably confusing the RT of `return` with the purity of `foo`. – chi Jan 06 '15 at 21:35

1 Answers1

3

At it's core, referentially transparency is about evaluating expressions. Fundamentally, it says that if you evaluate an expression in a context, it will evaluate to the same value if you evaluate it in any identical context.

Except that "return" statements don't evaluate to anything at all. They cause the current call of the enclosing method to evaluate to something. There's no way that fits the concept of referential transparency. The "throw" statement has a similar problem.

For the examples, the first one

def foo(n:Int): Int = return n + 1

is benign but verbose and non-idiomatic. The second one

def foo(ns: List[Int]): Any = ns.map(n => return n + 1)

is much more problematic. If passed the empty list, it returns the empty list. If passed a non empty list, it returns the value of the head of the list plus 1.

Dave Griffith
  • 20,435
  • 3
  • 55
  • 76
  • 5
    WHy is the second a problem? `= if (ns.isEmpty) () else ns.head + 1` has the same behaviour without the `return`? – The Archetypal Paul Jan 06 '15 at 14:31
  • Because the naive reading (in which the return becomes the function evaluation, rather than the method) is ns.map(_+1), is almost certainly what the programmer intended. Much more likely that the "return" is a stray Java-ism, than that the semantics you describe are actually what the programmer meant to say. – Dave Griffith Jan 06 '15 at 15:14
  • 3
    I agree it could be a mistake. I guess I'm missing the connection with breaking referential transparency – The Archetypal Paul Jan 06 '15 at 15:23