"JavaScript's catch and finally aren't so different either"
I realized afterwards that you can define protect in terms of on-err, but that isn't quite the same as using the same operator for both use cases. And, uh, that code looks awfully intimidating, so please forgive me for not looking deeply into it and trying to understand it.
In any case, my question still hasn't been answered: is there any use case for this at all?
"I realized afterwards that you can define protect in terms of on-err"
Nah. While that's a straightforward analogy from catch and finally, 'protect deals with continuation early exits (not seen in JavaScript), whereas 'on-err isn't supposed to. Jarc's 'on-err did for a while, but I seem to remember that being fixed.
---
"And, uh, that code looks awfully intimidating, so please forgive me for not looking deeply into it and trying to understand it."
Fair enough. ^_^
Just in case anyone wants to use that monstrous code, feel free.
---
"In any case, my question still hasn't been answered: is there any use case for this at all?"
Inasmuch as a language designer is trying to expose as much as possible to the programmer, even things they don't expect to be useful, that's not a question that needs an answer. The real question is "Why not?"
But dido spelled out at least one goal: "I do believe that there should be some way to retrieve the original exception, rather than the last one raised by protect handlers"
I'm guessing dido's point is that a buggy protect handler shouldn't keep the programmer from discovering bugs under its protection. (It's being overprotective? :-p ) For instance, dido might like to see both errors at the command line.
---
For you and anyone else who didn't read the 'refl-dynamic-wind code, here's an outline of the guards' inputs and outputs, so you can get a sense of the flexibility it gives to the programmer:
; Possible inputs to the entry guard:
(enter)
(unknown-ccc)
; Possible results of the entry guard:
(enter) ; only if (enter) was the input
(raise <error>)
(unknown-ccc) ; only if (unknown-ccc) was the input
(known-ccc <destination continuation>)
; Possible inputs to the exit guard:
(return <value>)
(raise <error>)
(unknown-ccc)
; Possible results of the exit guard:
(return <value>)
(raise <error>)
(unknown-ccc)
(known-ccc <destination continuation>)
(It could also help to read the examples I posted, which are at the bottom of that giant code block.)
Come to think of it, it's probably possible to keep hacking on 'refl-dynamic-wind until the interface is like this:
; Possible inputs to the entry guard:
(enter)
(continue <destination>)
; Possible inputs to the exit guard:
(return <value>)
(raise <error>)
(continue <destination>)
; Possible results of either guard:
(enter)
(return <value>)
(raise <error>)
(continue <destination>)
I'd like to point out that this interface isn't the full extent of what the language designer might like to expose to the programmer.
For instance, in Kernel, continuation guards have access to both the destination continuation and the value being passed to it. If we implemented 'refl-dynamic-wind there, every one of the (continue <destination>) cases above could become (continue <destination> <value>).
If an Arc implementation provided that extended interface, it would make for a more flexible language from a dynamic standpoint and a less predictable language from a static standpoint.