Re: [racket-users] Error handling for the GUI

2019-03-26 Thread Greg Hendershott
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

2019-03-26 Thread Philip McGrath
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

2019-03-25 Thread James Platt


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

2019-03-25 Thread Matthias Felleisen



> 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

2019-03-25 Thread James Platt


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

2019-03-25 Thread Matthias Felleisen



> 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

2019-03-25 Thread James Platt


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

2019-03-23 Thread Greg Hendershott
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

2019-03-23 Thread Ben Greenman
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

2019-03-23 Thread David Storrs
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

2019-03-22 Thread Alex Harsanyi

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

2019-03-22 Thread James Platt
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.