Using `exn->string` from `racket/exn` should usually include context
("stack trace")?

  
https://docs.racket-lang.org/reference/exns.html#(def._((lib._racket%2Fexn..rkt)._exn-~3estring))

Also there will be more context to see, if in DrRacket or racket-mode
you've selected that higher level.


p.s. It's probably worth considering that many exceptions are
surprises about the world outside the program. File or network ports
couldn't be opened, read, written. Files didn't exist, or can't be
made not to exist. And so on. A program must deal with those, somehow.
Usually the exns will be something the user needs to see in the (G)UI,
ideally with a simplified message in their language, then the program
can hopefully resume just fine.

But -- contract violations aren't like that. They're about some code
surprising some other code. I think the only hope here is, run the
code enough (before the user ever does) to flush out the bad code
assumptions and fix them. Realistically that means having enough
automated tests, and running them frequently enough (like on every
code commit, or at least push, and you can't merge to master if tests
don't pass, etc.).

Because, there's rarely any good thing to tell the user, beyond
"internal error" + cryptic data for them to give tech support. In some
cases, the program is even in a state where it shouldn't continue
running and should exit. Taking the "do nothing" branch followed by
"do something" might be bad times for the user and their data. For
example, not saving new changes they made, is bad -- but it's not as
bad as also corrupting previously saved data.  Even when it's not that
dire, a contract violation usually means there aren't any great
choices.

I'm sorry if any of that sounds preachy!  TL;DR: Although it makes
sense for contract violations to be exn:fail:contract, but they're
really unlike most exn:fails. Contracts are more like ASSERTs in old
school C, and the traditional way to handle assertion failures is to
abend.

On Sat, Mar 23, 2019 at 4:03 PM Ben Greenman
<benjaminlgreen...@gmail.com> wrote:
>
> On 3/23/19, David Storrs <david.sto...@gmail.com> wrote:
> > Alex makes good points, but I'm curious about the original question:  Is
> > there a straightforward way to tell which function it was whose contract
> > was violated, aside from parsing the message?  Or, more generally, where a
> > specific exception came from?
>
> For blame errors, it might help to grab the blame object and ask it
> some questions.
>
> ```
>   #lang racket
>
>   (module a racket
>     (provide (contract-out (f (-> symbol? symbol?))))
>     (define (f sym)
>       (symbol->string sym)))
>   (require 'a)
>
>   (with-handlers ((exn:fail:contract:blame?
>                     (lambda (blame-err)
>                       (define b (exn:fail:contract:blame-object blame-err))
>                       (printf "bad value = ~s~n" (blame-value b)))))
>     (f 'X))
>   ;; bad value = f
> ```
>
> Docs:
> https://docs.racket-lang.org/reference/Building_New_Contract_Combinators.html#(part._.Blame_.Objects)
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to