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
_________________________
Racket Developers list:
http://lists.racket-lang.org/dev