Hacker News new | ask | show | jobs
by SemanticStrengh 1512 days ago
Coroutines are much less coloured than async await programming though since functions returns resolved types directly instead of futures. But yes there is the notion of coroutine scope but I don't see how to supress it without making it less expressive.

Very few people know it but Oracle is developping an alternative to Loom, in parallel. https://github.com/oracle/graal/pull/4114

BTW i expect Kotlin coroutines to leverage loom eventually.

As for the tailrecursive keyword, it is not a constraint but a feature since it guarantee at the type level that this function cannot stack overflow. Few people know there is an alternative to tailrecursive, that can make any function stackoverflow safe by leveraging the heap via continuations https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deep-re...

As for Java, there is universal support for tail recursion at the bytecode level https://github.com/Sipkab/jvm-tail-recursion

3 comments

Thanks for posting that link to Java tail recursion library, super handy + didn't know about it. You need tail recursion for writing expression evaluators/visitors frequently.

I've been using an IntelliJ extension that can do magic by rewriting recursive functions to stateful stack-based code for performance, but it spits out very ugly code:

https://github.com/andreisilviudragnea/remove-recursion-insp...

  > "This inspection detects methods containing recursive calls (not just tail recursive calls) and removes the recursion from the method body, while preserving the original semantics of the code. However, the resulting code becomes rather obfuscated if the control flow in the recursive method is complex."
It was this guy's whole Bachelor thesis I guess:

https://github.com/andreisilviudragnea/remove-recursion-insp...

> Coroutines are much less coloured than async await programming though since functions returns resolved types directly instead of futures

Only because the compiler does its magic behind the scenes and transforms it into bytecode that takes a lambda with a continuation. Try calling a suspend function from java or starting a job and surprise, it's continuations all the way down

yes interfacing with java is generally made via RxJava and reactor. Interfacing is easy but yes nobody wants to use rxjava and reactor in the first place.. I wonder wether loom will enable easier interop and make the magic work from java side POV
> Coroutines are much less coloured

I think another commenter pointed out that they are still coloured though. Still, they're very cool - and you can use them for more than just lightweight threading.

> As for the tailrecursive keyword, it is not a constraint but a feature since it guarantee at the type level that this function cannot stack overflow

I'd say tailrecursive is compiler feature (codegen the recursion into a loop) to work around a runtime contraint (no tail call optimisation).

The lack of tail call optimisation on the JRE means recursion is a lot less safe than in functional language runtimes which guarantee stacks don't overflow when you make tail calls.

> As for Java, there is universal support for tail recursion at the bytecode level.

Just a note here for other readers that there are several terms in play here.

I was talking about "tail calls" - when a function calls a function as its last operation - and I mentioned some annotations to do "tail recursion", which is a special case - when a function calls _itself_ as its last operation.

SemanticStrength is talking about "tail recursion" only here. The JVM bytecode can support tail recursion (tail calls on the same method), since we can use the same bytecode that is used for while loops, etc.

However, we cannot do safe tail recursion between different functions (yet), in the same way that we cannot have a loop spanning more than one function. Tail call optimisation is something that will hopefully come in Project Loom.

Doesn’t it possibly get inlined by current mechanisms as well?
Can you explain a bit more?
I am absolutely a novice at this level of detail with the current OpenJDK implementation, so I’m only asking it, but wouldn’t a method call as a last operation be also a target of the basic inlining done by the JIT compilers? How is a non-recursive tail-call any different than an inline at any another location?