User Guide - Part Two
Yesterday I said I was going to show what tail-calls look like, not how they will look like. That's because nothing will be changed, except perhaps you, the programmer - who may start using them a lot more.
But what are tail-calls anyway? Tail-calls are function calls - or method calls, in Javanese - done in tail position. What the hell is tail position? Well, something is in tail position, if it's done just before you do a return.
Confusing? Lets see some examples of what this means in Java:
// first example
methodCall();
return;
// second example
return methodCall();
As you can see, tail-calls come in two shapes in Java: they're either a method call followed by a
void
return
, or a return
of a method call.Is it that simple? Yep, pretty much. Well, no. In fact, tail-calls always look like this, but these aren't always tail-calls.
Imagine, in our first example above,
methodCall
returns an int
. This int
has to be discarded by the JVM, before control is returned to our parent method, so the method call isn't quite the last thing that's being done before the return
.Now take our second example, and consider that
methodCall
returns a float
but the method we are returning from returns a double
. The JVM must coerce the float
returned by methodCall
to a double
before returning from this method, so again that function call isn't the last thing done before the return
. Depending on your compiler (which is javac
, most likely) some coercions do work (byte
, short
and char
to int
, and coercions amongst objects without casts).All this details mean that, if you do come to depend on tail-calls, you must beware of these issues. Other, simpler, examples where “tail-calls don't work” are:
// first example
synchronized (obj) {
return methodCall();
}
// second example
try {
return methodCall();
} catch (Exception e) {
// ...
} finally {
// ...
}
Clearly, on both examples, there are things to be done after the method call - to release the lock, to handle exceptions and to run finallies - so these aren't really tail-calls.
But hey, what's so special about tail-calls? Well, remember all that stuff about them being the very last thing done in a method? If there's nothing more to be done in that method, you can simply jump to the other method and ignore the caller and its frame. This both reduces stack space, allows the earlier collection of some local variables, and promotes a recursion oriented programming style.
That's all there is to know about tail-calls. Tomorrow, continuations will follow.
No comments:
Post a Comment