3 ms·
Which languages do support TCO at this point? From my recollection we have * Scheme * Haskell * Elixir * Erlang * OCaml * F# * Scala * (not Clojure) *
by kevindamm 1y ago
Which languages do support TCO at this point? From my recollection we have
* Scheme
* Haskell
* Elixir
* Erlang
* OCaml
* F#
* Scala
* (not Clojure)
* the JVM could remove tail-recursive calls, but IIRC this still hasn't been added for security reasons
* Racket
* Zig
* Lua
* Common Lisp, under certain compilers/interpreters
* Rust? (depends)
* Swift? (sometimes)
- nhubbard 1y agoKotlin as well, through the ‘tailrec’ marker on a function.
- kevindamm 1y agoah, thanks, good to know.. but does that make it optional? I kind of like how ocaml requires a letrec annotation on any recursive definition and I don't know when you wouldn't want to add tailrec
- louthy 1y ago> * F# The .NET CLR supports the ‘.tail’ opcode which means that any .NET based language could support it. I’m hoping one day the C# team will get around to it. It seems like such low hanging fruit.
- alexisread 1y agoFreeforth (implicit) and Ableforth (deliberately explicit)
- taeric 1y agoI don't understand the security reasons on not removing tail calls. Any chance you have a good place to read up on that?
- kevindamm 1y agoIt was raised in one of the initial proposals, back in 2002 https://bugs.java.com/bugdatabase/view_bug?bug_id=4726340 https://bugs.java.com/bugdatabase/view_bug?bug_id=4726340 but that looks like a dead link and no wayback archive.. IIRC, basically it's because some parts of the JVM use stack unwinding to figure out what userland code is calling certain system code.. also the current stack frame has metadata about lock status used for allowing re-entrant locks that you lose if you elide the entire recursive call (which the initial proposal did by only removing the few bytecode instructions that set up the callstack frame and return from it). A more informal proposal from ~2016 allows for soft tail calls and hard (annotated) tail calls, with some restrictions that evidently avoid issues with system calls and lock/reentry maintenance: https://web.archive.org/web/20161112163441/https://blogs.oracle.com/jrose/entry/tail_calls_in_the_vm https://web.archive.org/web/20161112163441/https://blogs.ora... And a video by one of the JVM architects at Oracle about adding TCO for Scala https://www.youtube.com/watch?v=2y5Pv4yN0b0&t=1h02m18s https://www.youtube.com/watch?v=2y5Pv4yN0b0&t=1h02m18s Also previously featured here on HN, a way to do it that avoids security concerns, by using goto instead of strictly deleting bytecode instructions: https://news.ycombinator.com/item?id=22945725 https://news.ycombinator.com/item?id=22945725
- zabzonk 1y agoC++, depending on compiler and other stuff.
- geoffhill 1y agoBoth Clang and GCC have musttail attributes than can force tail calls at specific return statements in C/C++.
- rudy6912 1y agoAlso Fennel, both implicitly and explicitly with `tail!`. Source: https://fennel-lang.org/reference#tail https://fennel-lang.org/reference#tail
- Quekid5 1y agoIt's worth noting that some (many?) languages[0] only support TCO as long as you're calling the function itself in tail position. The usual cases were you'll notice this when implementing state machines in "direct style" or when doing continuation-passing style for control flow. TCO is more general than that in some languages where any function call in tail position can be turned into a direct jump. This obviously requires either 1) runtime support in some form or 2) a non-trivial amount of program transformation during compilation. [0] Scala's @tailrec is one I'm 100% certain of.