If you want to have code work everywhere and thus code defensively, yes. Of course you're not coding defensively when coding for Racket, either. But I guess I may have misunderstood you--Racket simply gives you a guarantee; as do some (other) Scheme implementations, so you get the same benefit with some/many other Scheme implementations as well--but even those "differ from Scheme (the standard)", by giving such a guarantee outside of the standard. It's not "Racket vs. Scheme implementations", it's "the (Racket|Scheme) implementations vs. Scheme (the standard)". Apologies then for my inappropriate rant about false claims.
> It is difficult to use the machine stack and have a fast call/cc. But I think Chez Scheme proves it's possible.
Chez doesn't seem to be using the machine stack either. I've tested with this code and "ulimit -s 1000" on Linux and it runs fine:
(define (conc a b)
(if (null? a)
b
(cons (car a)
(conc (cdr a) b))))
(define (iot n)
(if (negative? n)
'()
(cons n (iot (- n 1)))))
(display (length (conc (iot 10000000) (iot 10000000))))
(newline)
Note that it can still be using a stack built from "machine" or C style arrays as building blocks--that's what I meant with "Some Scheme implementations allocate stack frames more efficiently than cons cells". Gambit falls into this category as well. But you can't have a single uninterrupted C style array as the stack (with no copying during GC like Chicken does) and implement call/cc efficiently. So I'd still say that implementing Scheme including call/cc efficiently means moving away from the stack controlled by ulimit -s, and once that is done it's easy/natural for an implementation to also offer unbounded stacks like Racket does.I don't know whether Chez still uses the same strategy, but a major part of Dybvig's thesis (very readable) was dedicated to explain the details of a possible implementation strategy.
It is difficult to use the machine stack and have a fast call/cc. But I think Chez Scheme proves it's possible.