However, this ignores most details of the problem. In fact, (re-entrant) continuations and exceptions can't be mixed in the same language: Common Lisp has not adopted `call/cc` for one because it's impossible or at least much harder to implement `unwind-protect` (`finally`) in the presence of `call/cc` [0].
The major difference is that continuations allow you to do this:
(defparam *global*)
(defparam *shadow-list* (list))
(defun foo (cont)
(setf *global* cont))
(with-open-file (f "~/file.log")
(loop
for line = (read-line stream nil 'eof)
until (eq line 'eof)
collect (cons line (call/cc foo)))
(*global* *shadow-list*)
(*global* *shadow-list*) ;; what is the state of the file here? what if there was an exception reading from the file?
Well, dynamic-wind itself does not do what unwind-protect does. You have to manually "save/resume" the dynamic environment with the after/before clauses of dynamic-wind.
To be fair, it's probably relatively easy to use dynamic-wind to raise some runtime error when trying to resume the continuation after the original context "ended".
It doesn't, no, but yes, that was my thought: write a version of with-open-file implemented in terms of dynamic-wind that raises a runtime error if you try to reenter. Better hope people are using call/cc for exception handling and not threading though...
The major difference is that continuations allow you to do this:
[0] https://groups.google.com/g/comp.lang.lisp/c/1Ggl_BUi3Yg/m/V...