[racket] Problem with response/output

From: Jay McCarthy (jay.mccarthy at gmail.com)
Date: Sat Mar 7 13:22:16 EST 2015

I'm catching up on this thread.

The contracts should all be "void?" and it says "void" then it's
probably a typo and an error. "void" is a function that takes any
number of arguments and returns "void", which is not false, so "void"
is like an "any/c" contract, except that it is less efficient. (The
contract system will not put the same kind of wrapper when the
function can return anything.)

I'm loathe to fix this typo though, because I suspect that a lot of
code relies on the "void" behavior. If anything, I should change it to
have "any" so that it is more efficient and has the same errors.

Jay


On Fri, Mar 6, 2015 at 9:09 PM, André Matheus <amatheus at mac.com> wrote:
> If I understood what Matthew said correctly, the point of the contract
> requiring void is to prevent
> an error when someone uses a function returning a string rather than writing
> to the output port.
>
> But in this case, response should require returning void too, right? What
> confused me more than
> the error message and the contracts was that the same function worked when
> creating a response
> but didn’t work when using response/output, but response/output simply
> creates a response with
> default values, so my understanding was that the function should either work
> or fail on both.
>
> Em 06/03/2015, à(s) 21:40, Alexis King <lexi.lambda at gmail.com> escreveu:
>
> I do sort of agree that the void? requirement is strange and unneeded. It’s
> usually only used to indicate that a function provided by some module
> returns #<void>, but callback functions are usually specified with any as
> the return value to allow precisely this sort of thing.
>
> On Mar 6, 2015, at 16:26, Matthew Butterick <mb at mbtype.com> wrote:
>
>> From the error message, I changed the lambda to return (void) and then it
>> worked.
>> I think maybe the contract is wrong but frankly I don't understand much
>> about contracts.
>
>
> The contract, by definition, is always right ;)
>
> In this case, `response/output` takes as its first argument a procedure that
> accepts an output-port and returns void. [1] In contract-speak this is
> commonly written with dot notation as:
>
> (output-port? . -> . void?)
>
> but it appears in error messages, like the one above, with the equivalent
> notation:
>
> (-> output-port? void?)
>
> Note also that the error says the contract violation was "in the range of
> the 1st argument of" ... [giant contract follows]. That helps track down the
> error. The contract for the first argument is '(-> output-port? void?)'.
> This is a procedure contract. And "the range of" a procedure contract means
> the contract on the return value. Which in this case is `void?`. So the
> complaint is that the procedure given in the first argument is returning
> '11' when it should be returning void.
>
> Why is (-> output-port? void?) the contract for the first arg of
> `response/output`? The idea is that you write to the output-port directly
> rather than returning a value to the caller. Insisting on void as a return
> value imposes an extra measure of discipline, and sets an expectation.
>
> The reason your 'not-working' dispatcher is not working is that
> `write-bytes` does two things: it sends bytes to the output port, but then
> also returns the number of bytes written. [2] So this procedure:
>
> (λ (op) (write-bytes #"Hello world" op))
>
> is defective because it returns the number of bytes. Meaning, it breaks the
> contract, which demands void. (That's also why your error is '11': that's
> the number of bytes in "Hello world").
>
> But your revised procedure:
>
> (λ (op) (write-bytes #"Hello world" op) (void))
>
> Meets the contract because it ignores the return value from `write-bytes`
> and returns (void) instead.
>
> You should repeat this technique whenever you use `response/output`.
>
> You can also look into `response/full` and `response/xexpr`, which can be a
> more convenient way of making simple HTML or text responses.
>
>
>
> [1]
> http://docs.racket-lang.org/web-server/http.html?q=response%2Foutput#%28def._%28%28lib._web-server%2Fhttp%2Fresponse-structs..rkt%29._response%2Foutput%29%29
>
> which cross-references
>
> http://docs.racket-lang.org/web-server/http.html?q=response%2Foutput#%28def._%28%28lib._web-server%2Fhttp%2Fresponse-structs..rkt%29._response%29%29
>
> [2]
> http://docs.racket-lang.org/reference/Byte_and_String_Output.html?q=write-bytes#%28def._%28%28quote._~23~25kernel%29._write-bytes%29%29
>
> which cross-references
>
> http://docs.racket-lang.org/reference/Byte_and_String_Output.html?q=write-bytes#%28def._%28%28quote._~23~25kernel%29._write-string%29%29
>
>
>
> On Fri, Mar 6, 2015 at 3:48 PM, André Matheus <amatheus at mac.com> wrote:
>>
>> Hi, starting a project of mine, I've setup a dispatch rule and a function
>> to return the response.
>> To make things simple, I've used response/output, with a lambda writing to
>> the output-port.
>> However, I've got the error:
>>
>> response/output: contract violation
>>   expected: void?
>>   given: 11
>>   in: the range of
>>       the 1st argument of
>>       (->*
>>        ((-> output-port? void?))
>>        (#:code
>>         number?
>>         #:headers
>>         (listof header?)
>>         #:message
>>         bytes?
>>         #:mime-type
>>         (or/c bytes? #f)
>>         #:seconds
>>         number?)
>>        response?)
>>   contract from:
>>       <pkgs>/web-server-lib/web-server/http/response-structs.rkt
>>   blaming: /home/amatheus/Dropbox/focus/todagendas/teste.rkt
>>    (assuming the contract is correct)
>>   at: <pkgs>/web-server-lib/web-server/http/response-structs.rkt:41.2
>>   context...:
>>    /usr/share/racket/collects/racket/contract/private/blame.rkt:143:0:
>> raise-blame-error16
>>
>> /usr/share/racket/pkgs/web-server-lib/web-server/http/response.rkt:115:12
>>
>> So I've tried to use a response, with the same lambda, and it worked.
>> From the error message, I changed the lambda to return (void) and then it
>> worked.
>>
>> I think maybe the contract is wrong but frankly I don't understand much
>> about contracts.
>>
>> I've setup some code that exposes the problem. Navigating to "/working"
>> and "/fixed" works
>> fine; navigating to "/not-working" exposes the problem.
>>
>> #lang racket
>> (require web-server/dispatch
>>          web-server/servlet-env
>>          net/url
>>          web-server/http/request-structs
>>          web-server/http/response-structs)
>>
>> (define (not-working req)
>>   (response/output (λ (op) (write-bytes #"Hello world" op))))
>>
>> (define (working req)
>>   (response
>>    301 #"OK"
>>    (current-seconds) TEXT/HTML-MIME-TYPE
>>    empty
>>    (λ (op) (write-bytes #"Hello world" op))))
>>
>> (define (fixed req)
>>   (response/output (λ (op) (write-bytes #"Hello world" op) (void))))
>>
>> (define (url->request u)
>>     (make-request #"GET" (string->url u) empty
>>                   (delay empty) #f "1.2.3.4" 80 "4.3.2.1"))
>>
>> (define-values (agenda-dispatch agenda-url)
>>   (dispatch-rules
>>    [("working") working]
>>    [("not-working")  not-working]
>>    [("fixed") fixed]))
>>
>> (define (main)
>>   (serve/servlet agenda-dispatch
>>                  #:servlet-regexp #rx""
>>                  #:servlet-path ""))
>>
>> (module+ main
>>   (main))
>>
>> The contracts in response-structs.rkt:
>>
>> (provide/contract
>>  [struct response
>>          ([code number?]
>>           [message bytes?]
>>           [seconds number?]
>>           [mime (or/c false/c bytes?)]
>>           [headers (listof header?)]
>>           [output (output-port? . -> . void)])]
>>  [response/full (-> number? bytes? number? (or/c false/c bytes?) (listof
>> header?) (listof bytes?) response?)]
>>  [response/output (->* ((-> output-port? void?))
>>                        (#:code number?
>>                         #:message bytes?
>>                         #:seconds number?
>>                         #:mime-type (or/c bytes? #f)
>>                         #:headers (listof header?))
>>                        response?)]
>>  [TEXT/HTML-MIME-TYPE bytes?])
>>
>> Is the contract wrong or am I doing something weird?
>>
>> Thanks,
>>
>> André
>>
>> ____________________
>>   Racket Users list:
>>   http://lists.racket-lang.org/users
>>
>
> ____________________
>  Racket Users list:
>  http://lists.racket-lang.org/users
>
>
>
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>



-- 
Jay McCarthy
http://jeapostrophe.github.io

           "Wherefore, be not weary in well-doing,
      for ye are laying the foundation of a great work.
And out of small things proceedeth that which is great."
                          - D&C 64:33


Posted on the users mailing list.