Re: [racket-users] Error handling for the GUI
My paragraph after that was ~= I don't understand the need to do anything with a exn:fail:contract except show the user and exit. IIUC that's already the default behavior for non-GUI Racket apps, when some code is being hopeless. 1. Some other codes notices and raises exn:fail:contract. 2. The uncaught exception handler displays the details. 3. The app exits -- before it can do any more harm. Can we agree that 2 and 3 is the best (or anyway least-worst) thing to do? That normally, no good step 4 exists? If not: No worries, I won't try to convince you here. If so: There might be conditions where 2 and 3 aren't happening at all, or well-enough. We could dig into that. (Maybe there aren't enough details for a good "crash report". Maybe a handler somewhere is eating exns. Maybe a GUI app, when run outside DrRacket, the user doesn't necessarily see the message (??). And so on.) On Mon, Mar 25, 2019 at 12:00 PM James Platt wrote: > > > On Mar 23, 2019, at 5:49 PM, Greg Hendershott wrote: > > > 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.). > > Yes, but contract violations are also, by definition, problems that have been > anticipated. You may not know why a function is, for example, being passed a > specific parameter that is the wrong data type or is empty when you said it > should be non-empty but you do know that that is what happened. It's enough > to go on for an error message. My hope was that contracts would provide a > more granular set of predicates to test for each of the possible violations. > > > -- > 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.
Re: [racket-users] Error handling for the GUI
As Ben pointed out, if the exception is a `real exn:fail:contract:blame`, you don't even need to parse the message string: #lang racket (define/contract (wants-exact x) (-> exact? exact?) x) (define/contract (wants-inexact x) (-> inexact? inexact?) x) (define (show-which-was-violated x) (with-handlers ([exn:fail:contract:blame? (λ (e) (blame-value (exn:fail:contract:blame-object e)))]) (wants-exact x) (wants-inexact x))) (map show-which-was-violated '(1 1.0)) ;; '(wants-inexact wants-exact) -Philip On Mon, Mar 25, 2019 at 1:11 PM James Platt wrote: > > On Mar 25, 2019, at 12:49 PM, Matthias Felleisen wrote: > > > See how precise the exn message is: 2nd arg of 1st arg of f ~~ not a > boolean? > > Okay. So the exn message is generated in a systematic way which I can > count on. I didn't realize that. Thanks. > > -- > 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.
Re: [racket-users] Error handling for the GUI
On Mar 25, 2019, at 12:49 PM, Matthias Felleisen wrote: > See how precise the exn message is: 2nd arg of 1st arg of f ~~ not a boolean? Okay. So the exn message is generated in a systematic way which I can count on. I didn't realize that. Thanks. -- 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.
Re: [racket-users] Error handling for the GUI
> On Mar 25, 2019, at 12:30 PM, James Platt wrote: > > > On Mar 25, 2019, at 12:05 PM, Matthias Felleisen wrote: > >> Your exception handlers may test a contract failure to any level. You can >> specify this in the predicate part of with-handlers or via match on the exn >> within the handler function. Regexp matching works well here. > > It's obvious enough how to use regex matching for this purpose. My concern > is partly that it ends up being a lot of code to write and partly that I was > assuming that the exact wording of error message details could change with > updates. Maybe these concerns are not so bad as I anticipate. > > From The Racket Guide, I did not get the impression that you could test a > contract at any level. Specifically, I don't see how you tell which > parameter caused the error. It could just be me not understanding something > that is actually obvious in the docs or maybe the docs need some work. As > usual, examples would help. I did search the web for examples of Racket code > including "exn:fail:contract" and found very little. Welcome to Racket v7.2.0.10. > (module a racket (provide (contract-out (f (-> (-> integer? boolean? string?) > string? (define (f g) (g 1 "not a bool"))) > (require 'a) > (f (lambda (x y) "hello world")) ; f: broke its own contract ; promised: boolean? ; produced: "not a bool" ; in: the 2nd argument of ; the 1st argument of ; (-> (-> integer? boolean? string?) string?) ; contract from: a ; blaming: a ;(assuming the contract is correct) ; at: stdin:2.41 ; [,bt for context] See how precise the exn message is: 2nd arg of 1st arg of f ~~ not a boolean? And best of all you can get at it programmatically via exn-message: > (with-handlers ((exn:fail:contract? exn-message)) (f (lambda (x y) "hello > world"))) "f: broke its own contract\n promised: boolean?\n produced: \"not a bool\"\n in: the 2nd argument of\n the 1st argument of\n (-> (-> integer? boolean? string?) string?)\n contract from: a\n blaming: a\n (assuming the contract is correct)\n at: stdin:2.41" -- 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.
Re: [racket-users] Error handling for the GUI
On Mar 25, 2019, at 12:05 PM, Matthias Felleisen wrote: > Your exception handlers may test a contract failure to any level. You can > specify this in the predicate part of with-handlers or via match on the exn > within the handler function. Regexp matching works well here. It's obvious enough how to use regex matching for this purpose. My concern is partly that it ends up being a lot of code to write and partly that I was assuming that the exact wording of error message details could change with updates. Maybe these concerns are not so bad as I anticipate. >From The Racket Guide, I did not get the impression that you could test a >contract at any level. Specifically, I don't see how you tell which parameter >caused the error. It could just be me not understanding something that is >actually obvious in the docs or maybe the docs need some work. As usual, >examples would help. I did search the web for examples of Racket code >including "exn:fail:contract" and found very little. -- 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.
Re: [racket-users] Error handling for the GUI
> On Mar 25, 2019, at 11:59 AM, James Platt wrote: > > > On Mar 23, 2019, at 5:49 PM, Greg Hendershott wrote: > >> 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.). > > Yes, but contract violations are also, by definition, problems that have been > anticipated. You may not know why a function is, for example, being passed a > specific parameter that is the wrong data type or is empty when you said it > should be non-empty but you do know that that is what happened. It's enough > to go on for an error message. My hope was that contracts would provide a > more granular set of predicates to test for each of the possible violations. Your exception handlers may test a contract failure to any level. You can specify this in the predicate part of with-handlers or via match on the exn within the handler function. Regexp matching works well here. — Mattthias -- 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.
Re: [racket-users] Error handling for the GUI
On Mar 23, 2019, at 5:49 PM, Greg Hendershott wrote: > 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.). Yes, but contract violations are also, by definition, problems that have been anticipated. You may not know why a function is, for example, being passed a specific parameter that is the wrong data type or is empty when you said it should be non-empty but you do know that that is what happened. It's enough to go on for an error message. My hope was that contracts would provide a more granular set of predicates to test for each of the possible violations. -- 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.
Re: [racket-users] Error handling for the GUI
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 wrote: > > On 3/23/19, David Storrs 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.
Re: [racket-users] Error handling for the GUI
On 3/23/19, David Storrs 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.
Re: [racket-users] Error handling for the GUI
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? On Fri, Mar 22, 2019 at 7:17 PM Alex Harsanyi wrote: > > On Saturday, March 23, 2019 at 5:17:22 AM UTC+8, James Platt wrote: >> >> Well, I might make some kind of compromise. What I don't want to allow >> is the possibility of the user experience being "I click on the button and >> nothing happens." > > > You can wrap each button callback with a `with-handlers` call that > displays a message box when an exception is raised inside the callback, but > this user interface might not be very pleasant to use. Also this will not > help you if your callback does something like: > > (when #f >;; rest of the code here >) > > >> Next worst is to display a raw error message which the user can only >> interpret by cutting and pasting it into a web search. > > > If the user can do nothing about this error except report it back to the > developer, you can just log this error to a file, display an "Internal > Error" dialog box and instruct the user to add the log file to their bug > report. > > >> So yes, I could just get that far and then try and fix all the bugs >> rather than try and handle every possible exception gracefully. > > > If you have a limited amount of time available, I would suggest you spend > a little of that time on code that displays "Internal Error" and most of > that time in detecting and fixing these bugs. You won't be able to fix all > of them, but you can go a long way of making the "Internal Error" dialog > box be a rare occurrence in your application. > > You should display more information to the user, only if the user can > actually do something to fix the problem (e.g if you cannot open a file, > tell the user which file you cannot open), otherwise your application > should just log the exception into a file, along with other debugging > information so you can reproduce the problem, than instruct the user to > report a bug and attach the log file. > > >> More likely, meet somewhere in the middle of those approaches. >> >> >> On Mar 22, 2019, at 4:55 PM, Robby Findler wrote: >> >> > I know this will sound silly, but you could just consider them bugs and >> the fix them? (I went through a similar thought process with DrRacket years >> ago and that was the conclusion I came to-- just slap an "internal error" >> message on it so people aren't confused about it being a bug in their >> program.) >> > >> > Robby >> > >> > On Fri, Mar 22, 2019 at 3:09 PM James Platt >> wrote: >> > I'm working on displaying informative error messages in a GUI and I >> have been finding that many of the things I need to handle are contract >> violations in downstream functions. The thing is that it seems like there >> ought to be a better way than the methods I can think of. >> > >> > It's very simple to use the predicate exn:fail:contract? to tell if >> there was a contract violation but this doesn't tell me which downstream >> function or which parameter caused the error. I could parse the full error >> message with regular expressions and use that to build my error message for >> the user. However, this turns out to be a lot of code and it also seems >> like it could break down if a future update to Racket or some package >> changes the wording of an error message. I could go to the downstream >> functions, remove their contracts and, instead, have them raise custom >> exceptions. Then catch those exceptions in the GUI code. Not only is this >> a lot of code to change but it seems wrong to start with code created >> according to good practice and then undo it for further improvement. >> > >> > So my question is whether there is a better way to do this than I am >> aware of? >> > >> > -- >> > 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...@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. > -- 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.
Re: [racket-users] Error handling for the GUI
On Saturday, March 23, 2019 at 5:17:22 AM UTC+8, James Platt wrote: > > Well, I might make some kind of compromise. What I don't want to allow is > the possibility of the user experience being "I click on the button and > nothing happens." You can wrap each button callback with a `with-handlers` call that displays a message box when an exception is raised inside the callback, but this user interface might not be very pleasant to use. Also this will not help you if your callback does something like: (when #f ;; rest of the code here ) > Next worst is to display a raw error message which the user can only > interpret by cutting and pasting it into a web search. If the user can do nothing about this error except report it back to the developer, you can just log this error to a file, display an "Internal Error" dialog box and instruct the user to add the log file to their bug report. > So yes, I could just get that far and then try and fix all the bugs rather > than try and handle every possible exception gracefully. If you have a limited amount of time available, I would suggest you spend a little of that time on code that displays "Internal Error" and most of that time in detecting and fixing these bugs. You won't be able to fix all of them, but you can go a long way of making the "Internal Error" dialog box be a rare occurrence in your application. You should display more information to the user, only if the user can actually do something to fix the problem (e.g if you cannot open a file, tell the user which file you cannot open), otherwise your application should just log the exception into a file, along with other debugging information so you can reproduce the problem, than instruct the user to report a bug and attach the log file. > More likely, meet somewhere in the middle of those approaches. > > > On Mar 22, 2019, at 4:55 PM, Robby Findler wrote: > > > I know this will sound silly, but you could just consider them bugs and > the fix them? (I went through a similar thought process with DrRacket years > ago and that was the conclusion I came to-- just slap an "internal error" > message on it so people aren't confused about it being a bug in their > program.) > > > > Robby > > > > On Fri, Mar 22, 2019 at 3:09 PM James Platt > wrote: > > I'm working on displaying informative error messages in a GUI and I have > been finding that many of the things I need to handle are contract > violations in downstream functions. The thing is that it seems like there > ought to be a better way than the methods I can think of. > > > > It's very simple to use the predicate exn:fail:contract? to tell if > there was a contract violation but this doesn't tell me which downstream > function or which parameter caused the error. I could parse the full error > message with regular expressions and use that to build my error message for > the user. However, this turns out to be a lot of code and it also seems > like it could break down if a future update to Racket or some package > changes the wording of an error message. I could go to the downstream > functions, remove their contracts and, instead, have them raise custom > exceptions. Then catch those exceptions in the GUI code. Not only is this > a lot of code to change but it seems wrong to start with code created > according to good practice and then undo it for further improvement. > > > > So my question is whether there is a better way to do this than I am > aware of? > > > > -- > > 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...@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.
Re: [racket-users] Error handling for the GUI
Well, I might make some kind of compromise. What I don't want to allow is the possibility of the user experience being "I click on the button and nothing happens." Next worst is to display a raw error message which the user can only interpret by cutting and pasting it into a web search. So yes, I could just get that far and then try and fix all the bugs rather than try and handle every possible exception gracefully. More likely, meet somewhere in the middle of those approaches. On Mar 22, 2019, at 4:55 PM, Robby Findler wrote: > I know this will sound silly, but you could just consider them bugs and the > fix them? (I went through a similar thought process with DrRacket years ago > and that was the conclusion I came to-- just slap an "internal error" message > on it so people aren't confused about it being a bug in their program.) > > Robby > > On Fri, Mar 22, 2019 at 3:09 PM James Platt wrote: > I'm working on displaying informative error messages in a GUI and I have been > finding that many of the things I need to handle are contract violations in > downstream functions. The thing is that it seems like there ought to be a > better way than the methods I can think of. > > It's very simple to use the predicate exn:fail:contract? to tell if there was > a contract violation but this doesn't tell me which downstream function or > which parameter caused the error. I could parse the full error message with > regular expressions and use that to build my error message for the user. > However, this turns out to be a lot of code and it also seems like it could > break down if a future update to Racket or some package changes the wording > of an error message. I could go to the downstream functions, remove their > contracts and, instead, have them raise custom exceptions. Then catch those > exceptions in the GUI code. Not only is this a lot of code to change but it > seems wrong to start with code created according to good practice and then > undo it for further improvement. > > So my question is whether there is a better way to do this than I am aware of? > > -- > 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.