[racket] Is this a bug in contracts?

From: Asumu Takikawa (asumu at ccs.neu.edu)
Date: Mon Jan 14 00:24:48 EST 2013

On 2013-01-13 22:02:44 -0500, Harry Spier wrote:
> Is this a bug in contracts?  When I ran the following code the
> contract in onion% didn't give me an error, yet the contract is on an
> "init sh" but the class doesn't have an "init sh" it has an
> "init-field sh".  See the line with the comment ;;;;;THIS LINE SHOULD
> USE init-field not init

No, this should be correct. An `init` specifies a subset of `init-field`
(it's not mutually exclusive with it).

> (define/contract onion%
>   (class/c [init (sh (is-a?/c shish-D%))]) ;;;;;THIS LINE SHOULD USE init-field not init
>   (class shish-D% (super-new)
>     (init-field sh)
>     (define/override (only-onions?)
>       (and (send sh only-onions?) #t))))
>
> (send (new onion% [sh (new onion% [sh (new skewer%)])]) only-onions?)

Notice here that if we change this to:

  (send (new onion% [sh 5]) only-onions?)

A contract error is raised appropriately because the init argument was
wrong, so the contract is clearly protecting the init argument. This is
the correct behavior, because an `init-field` clause just defines both
an init argument and a field. The class system doesn't track a separate
`init-field` thing.  If you only specify the init contract, it only
protects the init part.

If you set the field like this:

  (set-field! sh (new onion% [sh (new onion% [sh (new skewer%)])]) 5)

It does not raise a contract error. If you want to protect both, you
either need to revise the contract to

  (class/c [init-field (sh (is-a?/c shish-D%))])

or

  (class/c [init (sh (is-a?/c shish-D%))]
           [field (sh (is-a?/c shish-D%))])

Cheers,
Asumu

Posted on the users mailing list.