Because right now there is support in JRuby's YARVMachine to handle a limited form of tail call optimization. Specifically, if the last call in a method is to the method we're in and the receiver of that call is the same as the current self, tail call optimization will happen. That allows JRuby to run this script:
def fact(n, acc)That will explode in both YARV and MRI, long before getting anywhere, since the stack goes out. But this will work correctly in JRuby with -y, provided that the tail call optimization is actually turned on. To turn it on, use $JAVA_OPTS and set the variable jruby.tailcall.enabled to true, like this:
if n == 0
fact n-1, n*acc
p fact(25000, 1)
JAVA_OPTS="-Djruby.tailcall.enabled=true"Of course, you need latest trunk for this to work, and you need to compile the YARV file as described in my previous post. But provided you have done that, the above will actually work perfectly, without deepening the stack at all. The reason this is not turned on by default in the YARVMachine is that it isn't completely safe yet. There is one small kink, which is that if you redefine the current method within the current method, and then call self, this will not work as expected. It should be easy to add checks for this behavior, though, so that will come soon.
jruby -y testRecFact.rbc
Of course, the big problem with something like this is the stack trace. How to handle it? The implementation behavior would make it look like those 25000 calls to fact was just a single one. In the same manner, trace methods won't get called.
But trunk will actually report when these tail calls have been done. Say you have a script like this:
def a(n)(it is designed to explode at a certain depth, of course.) In current JRuby trunk, executed with -y, this will generate an output that looks like this:
if n > 20000
testRaise.rb:-1:in `a' TAIL CALL(20001): hell (RuntimeError)So it is quite obvious that the exception was raised in the 20001:th invocation of 'a'.
This work goes forward very fast, and it's funny to see progress happen this quickly. Yesterday SASADA Koichi visited the #jruby and #rubinius IRC channels, and we had some very interesting discussions on further collaboration. The future looks bright indeed, and this weekend I'll probably have time enough to take a first crack at a YARV compiler for JRuby.