[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Scheme-reports] 6.1 Exceptions needs examples

* Aaron W. Hsu [2012-03-22 17:09] writes:

>> 1. When no cond-clause matches, guard re-raises the condition in the
>>    dynamic context of the guard form.  This is similar to Java's
>>    try-catch (+ the implicit re-throw).
> It is possible to do this with the current guard form explicitly, but it
> is not possible to go the other way easily.


>> 2. Evaluate the cond-tests in the dynamic environment of the original
>>    raise.  The advantage of this strategy is that it preserves the
>>    context of the error; which is useful for debugging.  This is
>> similar
>>    to Common Lisp's HANDLER-CASE.
> This is already the semantics of normal raise or raise-continuable calls
> using with-exception-handler, and thus, already provided for.

Note that I said the "cond-tests". Only the cond-tests are evaluated in
the dynamic environment of raise; the <expression>s of the matching
cond-clause are evaluated in the dynamic environment of the guard

> Guards
> should not generally result in any loss of error information, and
> usually, a guard is the wrong thing to use if you intend to halt
> computation, or if you want to handle continuable notifications that
> should return to the normal flow of things.  Guards are designed for
> handling the cases where an error in the computation of the body
> prevents further reasonable execution of that body, but which does not
> necessarily stop the entire computation outside of the body.  The guard
> allows one to easily provide a result to the outer context in the cases
> when it may be impossible to get a reasonable result from the body form.
> This is more difficult to accomplish in a nice way using the existing
> semantics of the other forms because you would have to explicitly
> capture a continuation around the code and then use an exception handler
> that called out to the continuation to get this same behavior. Even that
> is not quite right because you do not necessarily want the dynamic
> extent of the body to pollute your response in the case where the body
> code is no longer helpful. 

guard can be expressed as macro that uses with-exception-handler and
raise.  See SRFI-34 for proof.

> As an example, convincing or otherwise:
> (define (notify-gui-maybe msg)
>   (define (alert) (display msg) (newline))
>   (guard (c [(error? c) (alert)])
>     (parameterize ([current-output-port gui-output-port])
>       (alert))))

As (error? c) does not depend on the dynamic environment this would do
the same with strategy 2 from above (just more efficiently).

> Here, I am thinking of a custom output port that reports messages into a
> gui window of some application.  However, there may be a problem, where
> perhaps the connection to the GUI is gone, or the window that the port
> relied on was closed by the user.  We want to do the guard outside so
> that we can retry the (alert) using the normal output port, but if there
> was another message that was signalled, such as a warning, then we
> really want that to occur inside the the parameterize so that it can
> take advantage of the gui message port. Thus, this back and forth
> behavior is exactly what we want in this case. Moreover, using the guard
> form, it is very clear what we are doing here, but if I were to write
> the same thing explicitly with continuations and with-exception-handler,
> things would get very hairy very quickly.  User's are likely to end up
> implementing this over and over again, because this pattern is common.
> It is better to have a common exception handling paradigm that supports
> this behavior from the start.
> I hope that this at least clarifies some of the rationale for guard.

I understand the reason to have a macro for a common use case but I
can't see why your example requires full continuations.


Scheme-reports mailing list