[racket] Contracts on subclasses/mixins
On 2012-09-10 12:35:52 -0700, Gregory Woodhouse wrote:
> Now, here's my question. provide grid% with its own contract-out
> clause. It seems rather redundant (and presumably unnecessary) to
> repeat the methods from base-grid% in the contract for grid%.
You don't need to repeat the contracts unless you actually override
these methods. You can think of class/c contracts as being tied to
a particular *implementation* of the method. If you don't
re-implement the method, specifying extra contracts only serves to
move around the responsibility for the implementation.
> My guess is that if I do not do this base-grid% will be blamed for any
> contract violations in the base class rather than grid%. Is this
> correct? Or will it even work? I don't mind if base-grid% is blamed
> for the contract violation. In fact, it may be preferable because it
> is more specific.
Yes, that should be correct. Here's a simple example that I think
illustrates what you're talking about:
#lang racket
(define/contract c1%
(class/c [f (->m odd? odd?)])
(class object%
(super-new)
;; broken method
(define/public (f x) 2)))
(define/contract (mix base)
(-> (class/c)
(class/c [g (->m odd?)]))
(class base
(super-new)
(inherit f)
(define/public (g) (f 1))))
(send (new (mix c1%)) f 2)
The method `f` is contracted only in the base class `c1%`.
When invoking the method on the result of the mixin with
a good argument, you get a contract violation blaming the
method implementation in `c1%`.
If, instead, you had overriden `f` in the mixin, then the
contract is not checked.
If it turns out that you want to say `f` should *always*
be protected by some contract no matter who implements it,
you might consider using an interface contract.
Cheers,
Asumu