If you are talking async and futures in Scala, it is imperative that you read SIP-14: Futures and Promises. There were also some extensive discussions about it on the SIP mailing list, which is a google group, so you can find its archives.
Now, I don't know much about Clojure and little about Scala, but I'll give it a shot.
First off, we need to differentiate between tail-CALLs and tail-RECURSION. Tail recursion is indeed rather easy to transform into a loop. With tail calls, it's much harder to impossible in the general case. You need to know what is being called, but with polymorphism and/or first-class functions, you rarely know that, so the compiler cannot know how to replace the call. Only at runtime you know the target code and can jump there without allocating another stack frame. For instance, the following fragment has a tail call and does not need any stack space when properly optimized (including TCO), yet it cannot be eliminated when compiling for the JVM:
function forward(obj: Callable<int, int>, arg: int) =
let arg1 <- arg + 1 in obj.call(arg1)
While it's just a tad inefficient here, there are whole programming styles (such as Continuation Passing Style or CPS) which have tons of tail calls and rarely ever return. Doing that without full TCO means you can only run tiny bits of code before running out of stack space.
What facility of the underlying virtual machine would allow the compiler to handle TCO more easily?
A tail call instruction, such as in the Lua 5.1 VM. Your example does not get much simpler. Mine becomes something like this:
push arg
push 1
add
load obj
tailcall Callable.call
// implicit return; stack frame was recycled
As a sidenote, I would not expect actual machines to be much smarter than the JVM.
You're right, they aren't. In fact, they are less smart and thus don't even know (much) about things like stack frames. That's precisely why one can pull tricks like re-using stack space and jumping to code without pushing a return address.
Best Answer
You can use
-print
when compiling Scala, and it will print a de-sugared version of the code. Unfortunately, you'll see that Scala has syntactic sugar for good reason.Let's see a very simple example:
And the output:
You'll often see things like
<empty>
-- these are compiler annotations, not valid Scala code. For example, a parameter in a case class will have its getter tagged with<stable> <caseaccessor> <accessor> <paramaccessor>
. Also, a case class will have a number of methods marked<synthetic>
, to indicate they were created by the compiler.Also, the
this
constructor you see here is not valid Scala code, exactly. In this case, the "normal" Scala constructor (which is the body of theclass
,trait
orobject
) is moved inside such athis
method -- which is how Java itself sees things.So, this is mixture of Scala and Java, with a bit of compiler internals sprinkled over it. But it will show the de-sugared stuff.