[racket-dev] [plt] Push #21701: master branch updated

From: Eli Barzilay (eli at barzilay.org)
Date: Fri Dec 10 11:22:55 EST 2010

Three hours ago, Robby Findler wrote:
> Okay. So I'll just start by spelling out the pieces of information
> that's there to be put into a message:
>  - is the contract blaming the party where the contract was written (or not)
>  - the source location where the contract was written down
>  - the contract, written out
>  - the names of the two parties
>  - a violation specific message with some details (ususally of the
>    form "expected an <integer?>, got #f" or similar)
> The current error message uses that first thing as a conditional and
> has a different sentence for each of those cases.

[Warning: see my earlier claim of being inexperienced, so use lots of

I think that "a sentence" is where the mistake starts -- it works for
short error messages (that are almost always on one line), but the
long contract error messages is what makes it annoying to me --
especially when there's so many bits there, which means that you
need more verbiage and the result is even less clear (I read it like a
story to myself, pointing at an imaginary side where my code and
another side where the other code is...).

How about this:

  client contract violation: <viloation message>
    at:       <name/source of client>
    contract: <contract>
    library:  <name/source of library>
    (contract from: <contract source>)


  library self-contract violation: <viloation message>
    library:  <name/source of library>
    contract: <contract>
    caller:   <name/source of client>
    (contract from: <contract source>)

The words don't matter much, but the idea is:

  * Show the error message first, that's the most important thing for
    me, for some cases like "expected an <integer?>, got #f" I'd
    probably know immediately where the problem is.

  * Show the faulty code next -- for almost all errors this in
    combination to the above is all I need to know.

  * Show the contract next, in more complex cases (like when I
    confused arguments and have multiple errors, I'll try to decipher

  * Show the library source, just in case there's some problem there
    (eg, I need to complain or make a feature request, or I'm the
    library author and I'm trying it).

  * And finally show the contract location (the least required bit of
    information for the error).

In addition, I made the message part appear first assuming that it's
usually small, and read as text.  The following bits of information
are all aligned to make them stick out nicely, and I expect that it
won't take me long before my eyes would learn to quickly jump to the
relevant information -- this also assumes that each of the bits take
one line.  The last one is not aligned, but it's aplpicable in cases
rare enough to not matter.  I don't think that there's any further
need for explanations (like "the error might be here, or there, or
there") -- I see where the contract is defined, and in the rare cases
where none of the lines make sense, I'll get there naturally to find
out how the bogus contract is defined.

It's very important (IMO) that the lines are short, for example

  at: /Users/clklein/tmp/contract-violator.rkt:9.17: (file /Users/clklein/tmp/contract-violator.rkt)

is bad since it will almost always wrap[*].  I prefer lots of
shorthands, like "<collects>/foo/bar.rkt" or
"<home>/tmp/contract-violator.rkt", as well as dropping out obvious
pieces: in the above case there's no need for the (file ...) part; in
a library require there's no need for the path.

[*] (Except for Kevin, who will laugh at the attempt to go beyond a
    1/4 of his screen's width...)
[*] (And except for Sam, who is blind to soft line breaks...)
[*] (Perhaps except for {everyone, except for people who like to use
    really big fonts}.)

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                    http://barzilay.org/                   Maze is Life!

Posted on the dev mailing list.