[racket-dev] Removing Xexpr preference from Web Server

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Mon Dec 6 12:39:18 EST 2010

This is starting to feel more like a clever hack and less like a
useful way to provide support for people wanting to use the web
server. Please correct me if I'm getting this wrong. Here's why I say
that:

One use I see of respnose/c is this:

 send/suspend : (-> (-> string response/c) request?)

The old world understanding of that is pretty straightforward, just do this:

(-> (-> string (or/c response/basic?
                     (cons/c bytes? (listof (or/c string? bytes?)))
                     pretty-xexpr/c))
    request?)

and then realize that the argument function I pass to send/suspend has
to return one of those three things.

Fine.

Now, in the new version, life is not so simple. My job, as a user of
send/suspend is to go find any place in the code where someone could
have set the thread-cell inside the paramter, see what they set it to,
figure out what the function they supply can return and then adjust my
function accordingly.

In other words, this seems like a step backwards from a "do I, as a
client of the webserver, understand the API of the webserver and can I
program to it?" perspective.

Does that seem right to you?

------

If I understood the discussion earlier, I think that there are a small
handful of things that are allowed there (in particular, you want to
go from 3 to 1 or something like that). So maybe what you should do is
change response/c to be explicitly documented as a morphable contract
that, based on a setting somewhere can either be the lax or the strict
version.

At least that way you are only requiring your clients to be aware of a
small number of requirements, not many.

(I guess that you can do even better than this by making the
requirements on the clients statically knowable, not dynamically
knowable, but I don' thave a concrete suggestion on how to do this
yet.)

Robby

On Mon, Dec 6, 2010 at 11:28 AM, Jay McCarthy <jay.mccarthy at gmail.com> wrote:
> On Mon, Dec 6, 2010 at 10:23 AM, Robby Findler <robby at eecs.northwestern.edu>
> wrote:
>>
>> On Mon, Dec 6, 2010 at 11:19 AM, Jay McCarthy <jay.mccarthy at gmail.com>
>> wrote:
>> >
>> >
>> > On Mon, Dec 6, 2010 at 10:16 AM, Robby Findler
>> > <robby at eecs.northwestern.edu>
>> > wrote:
>> >>
>> >> Who should be blamed if the coercion does not return a response?
>> >
>> > The provider of the coercion should be blamed, but that is not possible
>> > [I
>> > think] so the positive party of the whole dynamic/c is blamed.
>>
>> Can you show us an example use of this contract from the web server?
>
> The HEAD Web Server has this definition of response/c:
> (define response/c
>   (or/c response/basic?
>         (cons/c bytes? (listof (or/c string? bytes?)))
>         pretty-xexpr/c))
> My local changes have:
> (define current-response/c
>   (make-parameter any/c))
> (define response/c
>   (dynamic/c any/c current-response/c response?))
> My compatibility library is just a module with this body:
> (current-response/c (coerce/c normalize-response))
> where normalize-response is the function (basically) that the old Web Server
> always used before relying on anything in particular about a response and
> coerce/c is a trivial thing that turns a coercion into a contract:
> (define (coerce/c i->o)
>   (make-contract
>    #:name (build-compound-type-name 'coerce i->o)
>    #:projection
>    (λ (b)
>      (λ (x)
>        (or (i->o x)
>            (raise-blame-error b x "Coercion failed"))))))
> My local copy will also provide xexpr-response/c:
> (define xexpr-response/c
>   (coerce/c
>    (λ (x)
>      (cond
>        [(response? x)
>         x]
>        [(xexpr? x)
>         (response/xexpr x)]
>        [else
>         #f]))))
> which many users will want to use as a current-response/c, although I will
> not ship any code that uses it exist for test cases.
> Jay
>
>>
>> >> Is there a contract on current-response/c? (I assume that the "/c"
>> >> there is a misnomer and it really is a parameter that holds a
>> >> contact/coercion, not a contract.)
>> >
>> > current-response/c is contracted with (parameter/c contract?)
>> > The /c is not a misnomer, you are just parsing it wrong. Read it as
>> > (parameter (contract response)) not (contract (parameter response)),
>> > where
>> > /c is the post-fix syntax for (contract x) and current- is the pre-fix
>> > syntax for (parameter x)
>>
>> Ah. I see.
>>
>> Robby
>>
>> >
>> >>
>> >> Robby
>> >>
>> >> On Mon, Dec 6, 2010 at 10:55 AM, Jay McCarthy <jay.mccarthy at gmail.com>
>> >> wrote:
>> >> > Maybe dynamic/c isn't clear enough... its definition is pretty short:
>> >> > (define (dynamic/c pre parameter post)
>> >> >   (define pre-ctc (coerce-contract 'pre pre))
>> >> >   (define post-ctc (coerce-contract 'post post))
>> >> >   (make-contract
>> >> >    #:name (build-compound-type-name 'dynamic pre-ctc parameter
>> >> > post-ctc)
>> >> >    #:projection
>> >> >    (λ (b)
>> >> >      (define pre-proj ((contract-projection pre-ctc) b))
>> >> >      (define post-proj ((contract-projection post-ctc) b))
>> >> >      (λ (x)
>> >> >        (define dyn-proj
>> >> >          ((contract-projection (coerce-contract 'dynamic
>> >> > (parameter)))
>> >> > b))
>> >> >        (post-proj
>> >> >         (dyn-proj
>> >> >          (pre-proj
>> >> >           x)))))))
>> >> > The system provides pre and post, so it can offer protection to the
>> >> > coercion
>> >> > as well as receive protection FROM the coercion. But the coercion
>> >> > comes
>> >> > from
>> >> > a parameter which is exposed to the user.
>> >> > The one I use in the web-server is:
>> >> > (dynamic/c any/c current-response/c response?)
>> >> > where response? is the data structure predicate that the internal
>> >> > plumbing
>> >> > uses.
>> >> > Jay
>> >> > On Mon, Dec 6, 2010 at 9:51 AM, Jay McCarthy <jay.mccarthy at gmail.com>
>> >> > wrote:
>> >> >>
>> >> >> That's why dynamic/c has a pre/c and post/c. Before it uses the
>> >> >> user's
>> >> >> contract, it applies pre/c. After it applies post/c. This ensures
>> >> >> that
>> >> >> the
>> >> >> user's contract actually coerces to a response?
>> >> >> Jay
>> >> >>
>> >> >> On Mon, Dec 6, 2010 at 9:25 AM, Robby Findler
>> >> >> <robby at eecs.northwestern.edu> wrote:
>> >> >>>
>> >> >>> On Mon, Dec 6, 2010 at 9:23 AM, Jay McCarthy
>> >> >>> <jay.mccarthy at gmail.com>
>> >> >>> wrote:
>> >> >>> > Yes, since I am allowing users to customize the coercion
>> >> >>> > behavior, I
>> >> >>> > could
>> >> >>> > either have them provide two functions: a coercion-applies?
>> >> >>> > function
>> >> >>> > and a
>> >> >>> > coercion function; OR I could have them just provide the coercion
>> >> >>> > function
>> >> >>> > and I will check the answer and re-run it inside of the function
>> >> >>> > body.
>> >> >>> >
>> >> >>> > The other issue is that finding all the places where I should
>> >> >>> > apply
>> >> >>> > the
>> >> >>> > coercion inside the body of the function is difficult, because I
>> >> >>> > need
>> >> >>> > to do
>> >> >>> > it at every place where a response/c could flow in (relatively
>> >> >>> > easy)
>> >> >>> > and
>> >> >>> > every place where a response/c could flow out (much hard, esp.
>> >> >>> > with
>> >> >>> > continuations). Contracts on functions are very nice in their
>> >> >>> > ability
>> >> >>> > to do
>> >> >>> > stuff to inputs and outputs.
>> >> >>>
>> >> >>>
>> >> >>> I think I need more help to understand the programming problem
>> >> >>> better.
>> >> >>> Why are your users supplying you a contract that you are using to
>> >> >>> protect your functions? That is how can you use anything about that
>> >> >>> contract to avoid errors in your programs?
>> >> >>>
>> >> >>> Robby
>> >> >>>
>> >> >>> > Jay
>> >> >>> >
>> >> >>> > On Mon, Dec 6, 2010 at 8:19 AM, Matthias Felleisen
>> >> >>> > <matthias at ccs.neu.edu>
>> >> >>> > wrote:
>> >> >>> >>
>> >> >>> >> The string->number primitive is probably closer to what Jay
>> >> >>> >> wants
>> >> >>> >> to
>> >> >>> >> do.
>> >> >>> >>
>> >> >>> >> The only contract I can think of for string->number is
>> >> >>> >>
>> >> >>> >>  ;; Number -> Boolean
>> >> >>> >>  (define (string->number-able? x)
>> >> >>> >>    (number? (string->number x)))
>> >> >>> >>
>> >> >>> >> So the real problem is a performance problem, which a lazy
>> >> >>> >> interpretation
>> >> >>> >> of contracts by the compiler might be able to eliminate.
>> >> >>> >>
>> >> >>> >> Is this the true problem Jay -- Matthias
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >> On Dec 6, 2010, at 9:45 AM, Robby Findler wrote:
>> >> >>> >>
>> >> >>> >> > Let's be clear here: our inability to enforce projectionness
>> >> >>> >> > is
>> >> >>> >> > in
>> >> >>> >> > no
>> >> >>> >> > way condoning the two coercianlike contracts that you have now
>> >> >>> >> > written.
>> >> >>> >> >
>> >> >>> >> > That said, the only value I see to contracts that only signal
>> >> >>> >> > errors
>> >> >>> >> > (or do nothing) is that programmers know what to expect from
>> >> >>> >> > them.
>> >> >>> >> > The
>> >> >>> >> > downsides you mention are well taken, of course.
>> >> >>> >> >
>> >> >>> >> > In this specific case, your message seems slightly confused:
>> >> >>> >> > certainly
>> >> >>> >> > you should be able to use a contract to ensure that the
>> >> >>> >> > coercion
>> >> >>> >> > will
>> >> >>> >> > always succeed. Let's assume you have done that and now
>> >> >>> >> > discuss
>> >> >>> >> > only
>> >> >>> >> > where the coercing bit of the "contract" goes. Is it in a
>> >> >>> >> > higher
>> >> >>> >> > order
>> >> >>> >> > position? Is it something that describes an interface to your
>> >> >>> >> > module
>> >> >>> >> > or can it be considered an internal detail?
>> >> >>> >> >
>> >> >>> >> > As a possible guide by analogy, consider the path-string?
>> >> >>> >> > Predicate.
>> >> >>> >> > It is the contract on many functions the ultimately is
>> >> >>> >> > connected
>> >> >>> >> > to
>> >> >>> >> > some kind of a coercion somehwere buried inside the racket
>> >> >>> >> > primitives
>> >> >>> >> > for dealing with the filesystem. Is that like what you want to
>> >> >>> >> > do?
>> >> >>> >> > If
>> >> >>> >> > so, how would your arguments hold up for that part of our
>> >> >>> >> > system?
>> >> >>> >> >
>> >> >>> >> > Robby
>> >> >>> >> >
>> >> >>> >> > On Monday, December 6, 2010, Jay McCarthy
>> >> >>> >> > <jay.mccarthy at gmail.com>
>> >> >>> >> > wrote:
>> >> >>> >> >> These contracts are not thrown "at dynamic places". The
>> >> >>> >> >> contract
>> >> >>> >> >> is
>> >> >>> >> >> always at the module boundary/etc, but its meaning if
>> >> >>> >> >> affected
>> >> >>> >> >> by
>> >> >>> >> >> the
>> >> >>> >> >> dynamic context of the particular boundary crossing. [1]
>> >> >>> >> >>
>> >> >>> >> >> I'm been thinking about why I want to use contracts for this
>> >> >>> >> >> purpose.
>> >> >>> >> >> The alternative is to put an any/c contract in all the places
>> >> >>> >> >> I
>> >> >>> >> >> currently have response/c and as the first thing in all those
>> >> >>> >> >> functions call
>> >> >>> >> >> current-any->response [or as the last thing on returns] on
>> >> >>> >> >> the
>> >> >>> >> >> input
>> >> >>> >> >> argument. I would then have to put a note in all the
>> >> >>> >> >> documentation
>> >> >>> >> >> of those
>> >> >>> >> >> any/c that it doesn't REALLY accept anything, instead in
>> >> >>> >> >> other
>> >> >>> >> >> accepts
>> >> >>> >> >> things that the dynamic current-any->response will turn into
>> >> >>> >> >> a
>> >> >>> >> >> response. If
>> >> >>> >> >> the coercion failed, then I would have to throw an error,
>> >> >>> >> >> which
>> >> >>> >> >> be
>> >> >>> >> >> purely
>> >> >>> >> >> dynamic with no blame information because it would not be
>> >> >>> >> >> associated with a
>> >> >>> >> >> contract boundary.
>> >> >>> >> >>
>> >> >>> >> >> In contrast, using a contract for this purpose allows me to
>> >> >>> >> >> centralize
>> >> >>> >> >> the documentation and behavior of these arguments, get
>> >> >>> >> >> correct
>> >> >>> >> >> blame on
>> >> >>> >> >> places where the coercion fails, and abstract the coercion
>> >> >>> >> >> out
>> >> >>> >> >> of
>> >> >>> >> >> the code
>> >> >>> >> >> that is using it into its interface. These are all great
>> >> >>> >> >> wins.
>> >> >>> >> >>
>> >> >>> >> >> In my opinion, if I did not use contracts, the only elegant
>> >> >>> >> >> thing
>> >> >>> >> >> to do
>> >> >>> >> >> would be to recreate something almost exactly like the
>> >> >>> >> >> contract
>> >> >>> >> >> system but
>> >> >>> >> >> called the coercion system. That is absurd to me when
>> >> >>> >> >> contracts
>> >> >>> >> >> already do
>> >> >>> >> >> exactly this.
>> >> >>> >> >>
>> >> >>> >> >> Am I just not clever enough to think of another elegant way?
>> >> >>> >> >> Why is there so much resistance to using the contract system
>> >> >>> >> >> in
>> >> >>> >> >> a
>> >> >>> >> >> perfectly legal way according to its own definition &
>> >> >>> >> >> contracts?
>> >> >>> >> >> [2] [i.e.
>> >> >>> >> >> "projection" functions are not forced to be projections by
>> >> >>> >> >> any
>> >> >>> >> >> means. /
>> >> >>> >> >> contracts already break eq?/equal?-ness / etc]
>> >> >>> >> >>
>> >> >>> >> >> Jay
>> >> >>> >> >> 1. We already have such context-sensitive contracts:
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >> >> http://docs.racket-lang.org/xml/index.html#(def._((lib._xml/main..rkt)._permissive/c))
>> >> >>> >> >>
>> >> >>> >> >> permissive/c exists to allow DrRacket to embed more snips
>> >> >>> >> >> inside
>> >> >>> >> >> the
>> >> >>> >> >> XML boxes, which are otherwise not XML elements.
>> >> >>> >> >> 2. make-contract's projection keyword has the contract (->
>> >> >>> >> >> any/c
>> >> >>> >> >> any/c)
>> >> >>> >> >>
>> >> >>> >> >> The example of make-contract coerces the procedure by
>> >> >>> >> >> restricting
>> >> >>> >> >> how
>> >> >>> >> >> many arguments rather than checking that when it is given
>> >> >>> >> >> that
>> >> >>> >> >> number of
>> >> >>> >> >> arguments it is used properly, etc.
>> >> >>> >> >>
>> >> >>> >> >> Only flat and chaperone contracts attempt to enforce
>> >> >>> >> >> projection-ness.
>> >> >>> >> >> On Sun, Dec 5, 2010 at 9:31 AM, Matthias Felleisen
>> >> >>> >> >> <matthias at ccs.neu.edu> wrote:
>> >> >>> >> >>
>> >> >>> >> >> Jay, coercions aka casts in our world are compound words with
>> >> >>> >> >> ->
>> >> >>> >> >> in
>> >> >>> >> >> between them. Why do you need a new name?
>> >> >>> >> >>
>> >> >>> >> >> (There is an inconsistency in their behavior. To wit
>> >> >>> >> >>
>> >> >>> >> >> Welcome to Racket v5.0.99.4.
>> >> >>> >> >>> (integer->char 1000000000000000)
>> >> >>> >> >> integer->char: expects argument of type <exact integer in
>> >> >>> >> >> [0,#x10FFFF],
>> >> >>> >> >> not in [#xD800,#xDFFF]>; given 1000000000000000
>> >> >>> >> >>
>> >> >>> >> >>  === context ===
>> >> >>> >> >> /Users/matthias/plt/collects/racket/private/misc.rkt:78:7
>> >> >>> >> >>> (string->number "a10")
>> >> >>> >> >> #f
>> >> >>> >> >>
>> >> >>> >> >> But that is a historical problem.)
>> >> >>> >> >>
>> >> >>> >> >> ;; ---
>> >> >>> >> >>
>> >> >>> >> >> I am also reluctant to throw contracts at dynamic places.
>> >> >>> >> >> Contract
>> >> >>> >> >> boundaries should be syntactically distinct, e.g., module
>> >> >>> >> >> boundaries or
>> >> >>> >> >> define/contract.
>> >> >>> >> >>
>> >> >>> >> >> ;; ---
>> >> >>> >> >>
>> >> >>> >> >> I think you're really just checking an assertion. So perhaps
>> >> >>> >> >> you
>> >> >>> >> >> want
>> >> >>> >> >> to go with /a as a suffix.
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >> >> -- Matthias
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >> >> --
>> >> >>> >> >> Jay McCarthy <jay at cs.byu.edu>
>> >> >>> >> >> Assistant Professor / Brigham Young University
>> >> >>> >> >> http://faculty.cs.byu.edu/~jay
>> >> >>> >> >>
>> >> >>> >> >> "The glory of God is Intelligence" - D&C 93
>> >> >>> >> >>
>> >> >>> >> >>
>> >> >>> >>
>> >> >>> >
>> >> >>> >
>> >> >>> >
>> >> >>> > --
>> >> >>> > Jay McCarthy <jay at cs.byu.edu>
>> >> >>> > Assistant Professor / Brigham Young University
>> >> >>> > http://faculty.cs.byu.edu/~jay
>> >> >>> >
>> >> >>> > "The glory of God is Intelligence" - D&C 93
>> >> >>> >
>> >> >>
>> >> >>
>> >> >>
>> >> >> --
>> >> >> Jay McCarthy <jay at cs.byu.edu>
>> >> >> Assistant Professor / Brigham Young University
>> >> >> http://faculty.cs.byu.edu/~jay
>> >> >>
>> >> >> "The glory of God is Intelligence" - D&C 93
>> >> >
>> >> >
>> >> >
>> >> > --
>> >> > Jay McCarthy <jay at cs.byu.edu>
>> >> > Assistant Professor / Brigham Young University
>> >> > http://faculty.cs.byu.edu/~jay
>> >> >
>> >> > "The glory of God is Intelligence" - D&C 93
>> >> >
>> >
>> >
>> >
>> > --
>> > Jay McCarthy <jay at cs.byu.edu>
>> > Assistant Professor / Brigham Young University
>> > http://faculty.cs.byu.edu/~jay
>> >
>> > "The glory of God is Intelligence" - D&C 93
>> >
>
>
>
> --
> Jay McCarthy <jay at cs.byu.edu>
> Assistant Professor / Brigham Young University
> http://faculty.cs.byu.edu/~jay
>
> "The glory of God is Intelligence" - D&C 93
>


Posted on the dev mailing list.