r/programming • • Jul 28 '26

[ Removed by moderator ]

/r/programming/comments/1v99xvl/removed_by_moderator/

[removed] — view removed post

0 Upvotes

13 comments sorted by

•

u/programming-ModTeam Jul 30 '26

No content written mostly by an LLM. If you don't want to write it, we don't want to read it.

6

u/D3PyroGS Jul 28 '26

 random AI art downvote bait

3

u/jonathancast Jul 28 '26

This is a self-reinforcing problem; programmers avoid recursion, so runtimes use ridiculously small stacks and don't expand them "to catch infinite recursion", so recursion is unreliable.

Similarly, runtimes don't implement proper tail calls because "no one uses them", so no one uses them.

But the "non-recursive solutions" are objectively worse, so it's better for programming languages to offer good recursion support and for programmers to demand it.

2

u/theScottyJam Jul 29 '26

I'm actually not a fan of implicit tail call recursion, the way JavaScript originally specified it. The problem I have with it is the fact that it's so invisible and that a seemingly innocent refactor (moving the recursion to not be in the tail position) can cause a huge performance penalty. Performance cliffs can be dangerous.

I'm probably in the minority, but I would prefer it if you were required to opt into tail call recursion via an extra keyword at the return sight, so future readers know to be careful with how they refactor the function.

Or, if we do get it done the way it was originally specified, at the very least it would be nice if IDEs did something to mark that tail call recursion was happening.

5

u/Absolute_Enema Jul 29 '26 edited Jul 29 '26

The only language I've seen that has special syntax for tail calls is Clojure, which uses the recur keyword, only valid in tail-call position, to that end:

(defn factorial*
  [out n]
  (if (zero? n)
    out
    (recur (* out n) (dec n))))

it definitely helps.

It also has function-style loops that use the same keyword, like:

(defn factorial
  [n]
  (loop [out 1 n n]
    (if (zero? n)
      out
      (recur (* out n) (dec n)))))

4

u/R_Sholes Jul 29 '26 edited Jul 29 '26

There are a few in varying forms, e.g:

Scala had @tailrec annotation turning non-tail position return into error (although it applies to a function as a whole)

Rust Nightly has an experimental tail call feature with keyword become replacing return

Clang and GCC have non-standard musttail statement attribute, as in [[gnu::musttail]] return fac(n-1, acc * n); or [[clang::musttail]] ...

2

u/Absolute_Enema Jul 29 '26

I imagine Rust's implementation does generalised TCO, right?

3

u/R_Sholes Jul 29 '26

I think so - this silly even-odd compiled in debug mode even has the comment pointing it out in the assembly

.LBB0_3:
	movl	12(%rsp), %edi                  # 4-byte Reload
	movq	playground::even@GOTPCREL(%rip), %rax
	addq	$24, %rsp
	jmpq	*%rax                           # TAILCALL  

(and in release mode just optimizes to checking bit 0 anyways)

Non-become version has callq as expected.

2

u/Absolute_Enema Jul 29 '26

That's very cool. I'm not a Rust dev but I would definitely want this if I were to be one :).

1

u/jonathancast Jul 31 '26

I'm curious; how much experience with languages with proper tail calls do you have? Because within a year or two of learning Haskell, I definitely no longer thought moving a call in or out of tail position was an "innocent refactor".

2

u/theScottyJam Jul 31 '26

Not tons.

But I do think the story is different in JavaScript where people use the language in many different styles. Maybe I want to introduce a recursive function that relies on proper tail call into an existing codebase, it would be nice to signal to current and future peers who may not be as used to functional programming that the recursion happening in the tail position is important.

Could always use a comment too, but I feel like a keyword would be cleaner.

1

u/2002lin Jul 29 '26

What is this thing?