Scala has already been doing it for quite some time now, but just within a single method.
It will happen by default where possible. If you want to be certain then use the @tailrec annotation on your method, which will force the compiler to emit an exception if it can't be done.
For anything "bigger", such as tail recursing across two or more methods, you'll need something like the trampoline functionality that scalaz provides.
--
You received this message because you are subscribed to the Google Groups "Java Posse" group.
To view this discussion on the web visit https://groups.google.com/d/msg/javaposse/-/VknSiMzz9kUJ.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.
JVM-level support would allow for tail recursion between two methods in otherwise unrelated classes to happen. Trampolining is a good workaround (or even implementation technique) but at the JVM level it would likely be a lot faster. Right now recursive algorithms pay a prohibitive penalty on the JVM, forcing programmers to choose between readable and fast.
--
You received this message because you are subscribed to the Google Groups "Java Posse" group.
To view this discussion on the web visit https://groups.google.com/d/msg/javaposse/-/cdKdk3n1vu0J.
Scala can only do it by transforming the recursive call into a jump at compile time - hence the single method restriction.
We *could* do better in theory, but only at the unacceptable expense of compatibility with other languages on the platform.
If the JVM did it, however, then this wouldn't be a problem.
You may also want to point your colleague in the direction of every improvement that John Rose has ever suggested. Fixnum's would be a pretty beneficial addition as well!
--
You received this message because you are subscribed to the Google Groups "Java Posse" group.
To view this discussion on the web visit https://groups.google.com/d/msg/javaposse/-/cdKdk3n1vu0J.
The other expense if Scala did it better would be separate compilation (being able to compile X and Y separately or together and getting the same bytecode out) unless it introduced a special Scala classloader, which I'm pretty sure was ruled out years ago.
Well, yes, there is that as a minor inconvenience as well :)
My personal opinion on TCO is that it is an academic boondoggle that nobody needs and only functional junkies care about, but then I'm tempering that rather arrogant opinion based on the fact that I've never managed to really get into the functional mindset, so maybe I just haven't seen the light yet. Still, rewriting a recursive method into a loop-based construct with i.e. a stack is so trivial, I just don't understand why people consider TCO to be such a big deal.
Implicit tail recursion (Where it's done anytime it looks like it is possible, vs. where it is only done if explicitly requested by the programmer) is not worth it. The actual number of recursive functions out there today is vanishingly small (though in these kinds of: 'Let's see what's out there now' approaches, there's always a bit of the tail wagging the dog: It is likely that more recursive functions would exist in the larger java ecosystem if TCO was part of the JVM!)... and it's not just a matter of realizing you can toss the current stack frame entirely right before jumping to the next method in line (or, as is usually the case, the same method, recursing):
* The stack trace is going to get completely screwed up. There will be an unexplainable break in the flow, where line X+1 of the stack trace is pointing to a call to a method that is _NOT_ the method on line X of the stack trace. What's actually happening is that there are a number of calls that have been ejected due to TCO. The last progress on JVM TCO still tracks these even across TCO jumps so that the stack trace is sensible. However, this does mean that, with this approach, you do eventually run out of memory anyway, because every TCO jump still has to keep track of a StackTraceElement. One easy way out is to make it explicit, both in that the programmer has to request it, and that the previous stack trace is marked as involving TCO when a TCO jump happens, so that in a stack trace you at least _SEE_ why there is a break in flow there.
* Resource Management (i.e. try/finally blocks) instantly kill TCO. The requirement that some method remains TCOable is a gigantic pain in the behind for code maintainers.
* The actual mechanics of writing a method that is TCO-able is complicated and not something the average java programmer understands. Why is 'return x;' TCO-able, but 'return x + 3;' isn't? This is not particularly hard to pick up, but, it's an entirely different can of worms that java programmers do not currently have to know about. Functional languages lack a bunch of baggage that java does have, but as java is not going to just take away features, adding this increases the total size of what you need to know to understand java. This is very bad.
My personal opinion on TCO is that it is an academic boondoggle that nobody needs and only functional junkies care about, but then I'm tempering that rather arrogant opinion based on the fact that I've never managed to really get into the functional mindset, so maybe I just haven't seen the light yet. Still, rewriting a recursive method into a loop-based construct with i.e. a stack is so trivial, I just don't understand why people consider TCO to be such a big deal.
As far as I know, TCO is not currently being worked on by Oracle for roughly the same reasons: It is not at all trivial, some awkward questions need to be answered, and the costs just don't seem worth it in the slightest. The primary reason work was done in the first place was to support other languages on the JVM better, which is a very valid reason to do it (as I tried to mention in the last point, in java TCO is a silly idea but in many other languages it's a key part of the language, and it would be nice if these languages don't have to hack together a class file that emulates it).
This is why Scala has `Either`, Haskell has `Maybe`
It's not just the methods, it's the data structures. For example, recursion makes a LOT of sense for iterating over an immutable linked list, and is often one of the first techniques taught within LISP. The need seems less apparent in an imperative/mutable paradigm, but I think it's fair to predict that we'll see less and less of this style as core counts follow the inevitable curve of Moore's law and as technologies like OpenCL become integrated into the Java ecosystem (NVidia's flagship GTX 690 has 3072 cores, and we're seeing this tech creeping back into CPUs...)
Only if tools are not adapted to show the presence of TCO in a stack trace. Which seems highly unlikely if this becomes a core JVM optimisation.
* Resource Management (i.e. try/finally blocks) instantly kill TCO. The requirement that some method remains TCOable is a gigantic pain in the behind for code maintainers.Try/finally blocks mess with almost any declarative/parallel technique available. This is why Scala has `Either`, Haskell has `Maybe` and Akka's futures will trap and return an Exception instead of throwing it.
Not least, the `return` statement itself. In almost all function languages the final expression evaluated in a function becomes the return. More than anything else, I've found this makes it far easier to reason about what can (and what can't) be optimised using tail-calls.
--
You received this message because you are subscribed to the Google Groups "Java Posse" group.
To view this discussion on the web visit https://groups.google.com/d/msg/javaposse/-/DRqmKhIqs44J.
To post to this group, send email to java...@googlegroups.com.
To unsubscribe from this group, send email to javaposse+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.
p.s. A immutable linked-list is just a series of "cells", each one holding a value and the rest of the list. All except the last one. Unless your mention of "tracker objects" is simply a synonym for these tail objects, then I suspect you may have misunderstood how the structure is implemented.
--
You received this message because you are subscribed to the Google Groups "Java Posse" group.
To view this discussion on the web visit https://groups.google.com/d/msg/javaposse/-/708D8_CoHygJ.
Not entirely so!
The "tracker" is another level of indirection, purposely added to the structure with the intent of making it mutable.
I'm quite sure that I was referring to immutable linked lists. Immutability isn't simply mutability with extra runtime exceptions, when a framework is built with immutability at it's core it works very differently.
The only place I know that does this in Java (the Lang) is joda time. Even guava lies by claiming that an immutable list is a subclass of a mutable one.