[Top][All Lists]

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

Re: GNU Guile 2.9.5 Released [beta]

From: Andy Wingo
Subject: Re: GNU Guile 2.9.5 Released [beta]
Date: Mon, 06 Jan 2020 21:34:59 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux)

On Mon 06 Jan 2020 00:26, Chris Vine <address@hidden> writes:

> I have a 'try' macro which adopts the approach that if an exception
> arises, the macro unwinds from the dynamic environment of the code
> where the exception arose to the dynamic environment of the call to
> 'try', evaluates the cond clauses in that environment, and then if no
> cond clause matches re-raises the exception in that environment with
> 'raise' (rather than 'raise-continuable').  In other words, it does
> stack unwinding in the same way as exception implementations in almost
> all other mainstream languages which use exceptions.  It would be
> trivial to implement this with guile-3.0's with-exception-handler with
> its unwind? argument set to true.

I am not sure this really matches with this use case:

  (define (call-with-backtrace thunk)
     (lambda (ret)
         (lambda (exn)
           (show-backtrace exn) ;; placeholder

  (define (false-on-file-errors thunk)
     (lambda (ret)
         (lambda (exn)
           (if (file-error? exn)
               (ret #f)
               (raise-continuable exn)))
  (define (foo f)
     (lambda ()
       (false-on-file-errors f))))
If there's an error while invoking `f' that's not a file error, you want
to have remained in the context of the error so you can show a full
backtrace.  To my mind this is central to the exception handler design.
So far so good I think.

If I change the implementation of `false-on-file-errors' to be:

  (define (false-on-file-errors thunk)
    (guard (exn ((file-error? exn) #f))

I think this change should preserve the not-unwinding environment that
`call-with-backtrace' expects.

> On the other hand, as you say it does not seem feasible to implement
> in guile the R6RS/R7RS requirement to unwind to the environment of the
> call to 'guard' when evaluating the cond clauses, and then return to
> the environment of the original exception in order to re-raise if no
> cond clause matches.

It's feasible, just not a good idea IMO.  The problem is that call/cc is
quite expensive.  Additionally that it captures the whole state of the
current thread, so a fiber ( with a `guard' may
error if it is preempted and migrated to a different CPU.

> Furthermore such a return is only relevant if the exception is to be
> re-raised with 'raise-continuable' instead of 'raise': it is pointless
> if the exception is re-raised with 'raise' because with 'raise' you
> can never get back there again.

FWIW I am not sure how raise-continuable will be used but it's a fairly
straightforward thing implementation-wise that doesn't bother me.

> I am somewhat influenced by my view of 'raise-continuable'.  I don't
> like it - how often does anyone use continuable exceptions, which seem
> to be a reimplementation of common lisp restarts?

I am not sure that they are restarts.  A restart to my mind is more

  (define (with-restart name thunk)
    (let lp ()
      (define tag (make-prompt-tag))
       (lambda ()
         (parameterize ((current-restarts (acons name tag (current-restart))))
       (lambda (k)

   (define (invoke-restart-by-name name . vals)
     (match (assoc name (current-restarts))
       ((name . tag)
        (apply abort-to-prompt tag vals))))

So you could invoke a restart within an exception handler but it has
nothing to do with whether raise or raise-continuable was used.  The
continuation captured by the equivalent of common lisp's `restart-case'
isn't the continuation that raises the error.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]