[racket] Contracts on subclasses/mixins

From: Asumu Takikawa (asumu at ccs.neu.edu)
Date: Mon Sep 10 16:23:38 EDT 2012

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

Posted on the users mailing list.