Exception for unhandled effect now carries the effect#11419
Exception for unhandled effect now carries the effect#11419kayceesrk wants to merge 14 commits intoocaml:trunkfrom
Conversation
08dbde2 to
793117d
Compare
|
I've confirmed that the PR passes the testsuite on Arm64. |
|
@kayceesrk Thank you---I learned a few things by checking what you did in amd64/arm64.S. I suppose we are not planning to support other architectures now? (I was very stuck on the assembly code for other architectures, and thus I am curious.) |
|
At the moment, trunk supports native code compilation only on |
Fix add_extension for Unhandled_effect
This comment was marked as resolved.
This comment was marked as resolved.
4f39852 to
29ff235
Compare
|
Thanks. Once this PR has been reviewed, I'll rebase the changes to look sensible. |
|
Pinging the whole of @ocaml/caml-devel again. This is a last-minute change to a stdlib API, something that we have botched in the past. Please review. 3 approvals will be required before this goes in 5.0. |
|
I suppose there's a technical reason for why this was not defined in the Also I don't see in the PR where this is defined in the |
Without heavily refactoring the runtime system,
It is as visible as other built-in stuff like |
Right but it's likely a good idea to have them properly documented somewhere no ? |
I think it makes sense to redefine the predefined exceptions as |
@Octachron what else would be needed to get to an approval? I'm feeling a bit guilty to ping @gasche, but he usually has a good taste for API design. Perhaps @sadiqj also as he understands the runtime system bits well. |
|
I'm pretty sure the implementation is fine. What I'm worried about is the design. This is what needs to be eyeballed, preferably by people who 1) use effects already in experimental libraries, or 2) have good taste in library design in general. The questions that pop in my mind at the moment:
|
|
|
||
| \begin{caml_example}{verbatim} | ||
| try bar () with Unhandled -> "Saw unhandled exception" | ||
| try bar () with Unhandled_effect F -> "Saw unhandled exception" |
There was a problem hiding this comment.
The message "Saw unhandled exception" is misleading. It should be "Observed an Unhandled_effect exception".
|
If possible, I would suggest avoiding the existence of two names for the same type or exception, such as |
|
@xavierleroy Thanks for the reference to |
I was hoping we would have the design discussion before implementing... |
Sure. Currently, on trunk, both With the I do not see any downsides to implementation. The fast paths, where no exceptions are raised, remain just as fast. The rare slow paths are marginally slower on native code due to the need to switch from OCaml to C stack to call the C functions that raise the corresponding exception. |
|
I am one of the early adopters of OCaml's algebraic effects, though I am not familiar with the OCaml internals. What I can provide is the perspectives of a user. I really like @xavierleroy's questions and here's my current assessment: Exception Registration (Question 1)From the end-user point of view, I could not see any differences between all these possible designs other than potential efficiency implications. Moreover, once the promised effect system arrives, none of these would matter because the type checker should prevent unhandled effects. I wanted val run : pool -> 'a task -> 'a
(** [...omitted by me, favonia...]
This function should be used at the top level to enclose the calls to other
functions that may await on promises. This includes {!await},
{!parallel_for} and its variants. Otherwise, those functions will raise
[Unhandled] exception. *)The current type system would not guarantee that this function is "used at the top level to enclose the calls to other functions". I wanted to provide good error messages to direct our users when they fail to follow the instructions. Once we embed the effects, I can use Therefore, from my point of view, how exactly the effect is embedded does not matter, as long as it does not slow down the successful
|
If we don't have any predefined exceptions for supporting effect handlers (as I propose to do), then this question does not apply. We will only have an |
|
Out of my curiosity, I suppose the current registration mechanism requires a concrete value of |
Yes. We'd need to declare an effect in the |
In some English-speaking communities "eff" is also used as a euphemised swear word ("eff off!"). |
|
I've opened #11423 which uses |
|
|
||
| exception Unhandled_effect : 'a eff -> exn | ||
| (** Exception raised when an effect is performed and there is no matching | ||
| handler for that effect. The argument is the unhandled effect. *) |
There was a problem hiding this comment.
This could be improved by doing the usual trick of writing an expression for the item and describe what it means/how it should be read. In this case:
(** [Unhandled e] is raised when effect [e] is performed and there is no handler for it. *)
| (** [perform e] performs an effect [e]. | ||
|
|
||
| @raise Unhandled if there is no active handler. *) | ||
| @raise Unhandled_effect if there is no active handler. *) |
There was a problem hiding this comment.
Is the concept of active handler defined somewhere (e.g. in supporting docs, sorry I hadn't the time to sift through them yet) ?
If not I don't like the term, it refers to something you can deactivate but AFAIK we are rather looking a syntactic property of programs (presence of a surrounding handler). Maybe simply:
@raise Unhandled e if there is no handler for [e].
| handler for that effect. The argument is the unhandled effect. *) | ||
|
|
||
| exception Continuation_already_taken | ||
| (** Exception raised when a continuation is resumed with a [continue] or |
There was a problem hiding this comment.
Please link to the functions, i.e. {!continue} or {!discontinue}.
There was a problem hiding this comment.
There is a Deep.continue and Shallow.continue and similarly two discontinues. I wasn't sure how to word it succinctly but also link to the right ones. Do you have a suggestion?
There was a problem hiding this comment.
I see. I'd first say then let's not have these two continue and discontinue bare naked. It's confusing, these names do not exist in this reading scope.
Also apparently there is even much more variants than what you mention. Since all these properly document that they @raise Continuation_already_taken, I don't think it's worth mentioning the names here.
What about one of these ?
(** Exception raised when a continuation is resumed for a second time. *)
(** Exception raised when a continuation is resumed twice. *)
(** Exception raised when a continuation is continued or discontinued a second time. *)
(** Exception raised when a continuation is continued or discontinued twice. *)
|
Gngngn, sorry these comments where meant to be made on the other PR. |
|
Superceded by #11423. To avoid confusion, let me close this PR. |
On trunk, when a program performs an effect that is not handled, we get the
Unhandledeffect.The exception above may be confusing since the term "Unhandled" may be applied to exceptions as well as effects. It is also not clear which effect was unhandled.
This PR renames the exception to
Unhandled_effectand also parameterizes it to carry the unhandled effect. With this PR,The change itself is small but I needed two bootstrap commits, one for adding the new exception and the second one for removing the old one. It is essential to keep both of these bootstrap commits separate so that forks of the compiler can merge the changes sensibly.
Fixes #11185.
Todo