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

From: Ryan Culpepper (ryan at cs.utah.edu)
Date: Mon Jun 25 23:53:13 EDT 2012

On 06/25/2012 09:27 PM, Stevie Strickland wrote:
> On Jun 25, 2012, at 11:21 PM, Ryan Culpepper wrote:
>
>> On 06/25/2012 09:04 PM, Asumu Takikawa wrote:
>>> On 2012-06-25 20:17:33 -0600, Ryan Culpepper wrote:
>>>> IIUC from your later message, you've implemented the generics
>>>> analogue of object/c (per-instance contract), whereas
>>>> prop:dict/contract is closer to class/c (per-type contract). It's a
>>>> little fuzzy because prop:dict/contract hacks in per-instance
>>>> contracts too in a kind of ad hoc way.
>>>
>>> That's a good point. The better analogy might be interface contracts vs.
>>> class/c. With generics, it is easy to control all points that an
>>> instance is created since constructors are just procedures. With
>>> classes, you can't get away with that since the instantiation forms are
>>> macros.
>>>
>>> The difference/advantage you might get with a per-type contract for
>>> generics is that you get a more interface-like blame story, as with
>>> interface contracts. Coverage isn't as much of an issue since you can
>>> just contract all constructors.
>>>
>>> Unfortunately, it's also not clear how to implement interface-like
>>> contracts for generics. Since the generics forms don't control the
>>> constructors, it's not obvious how to instantiate the blame at the
>>> construction site.
>>
>> You don't want to blame the construction site; the relevant party is the implementation site, where the generic interface is associated with concrete methods within a 'struct' form. See the docs for 'struct-type-property/c' for an example.
>
> Well, there are two blame parties, right?
>
> Much like interface contracts mediate between the creator of a class (that implements the interface) and the client of that class (that instantiates objects from that interface), I would think the contracts for a generic interface would be between the creator of a specific instance (the implementation site) and the user of that specific instance (the constructor site).
>
> Stevie

The analogy to interface contracts doesn't help me, because I don't know 
anything about them. But I think I disagree.

(module GEN racket
   ....
   (define-generics has-prime
     (get-a-prime has-prime))
   (provide-generics-with-contract
     (has-prime [get-a-prime (-> has-prime? prime?)])))

(module IMPL racket
   ....
   (struct prime-box (val)
     #:methods gen:has-prime
     [(define (get-a-prime self) (prime-box-val self))])
   (provide (struct-out prime-box)))

(module CLIENT racket
   ....
   (define p (prime-box 4))
   (get-a-prime p)) ;; ERROR

I think IMPL should be blamed for violating the contract on gen:has-prime.

As I see it, GEN establishes an obligation on implementors of 
'has-prime'. IMPL provides an implementation that turns out to be 
faulty; it doesn't live up to the obligation imposed by GEN. CLIENT is 
blameless; I don't see how the location of the constructor call has 
anything to do with it.

Ryan

Posted on the dev mailing list.