The following is a CLOS example which illustrates contravariance violation.
(defclass super ()
( (sl :type number :accessor s1) )
)
(defclass sub (super)
( (s1 :type integer :accessor s1) )
)
(defun do-bad ()
(let ( (subi (make-instance 'super))
(sup NIL))
(declare (type super sup) (type sub subi))
(setf sup subi)
(setf (s1 sup) 1.2)))
The compiler type checks the function body OK, because the assignment
of subtyped identifier to a supertyped one is OK. Subclass objects
should be usable wherever their less specialized superclass objects
are. The type of the slot accessor new value argument for sub is
(and integer number), effectively just integer, since that is the most
restrictive type. The type of the new value argument for the super
slot accessor is number, so the setf checks OK. However, at run time,
there is no method matching, since the slot accessor for sub cannot
take a new value float.
Like I said, I don't want to get into a religious argument about whether
static typing is good or bad. But the very least one would expect from
the type system in an object-oriented language is that it would enable
you to write code that didn't get a no matching method message at run time.
You might also want to use it to get better performance in some way.
Incidently, the Eiffel programming language, which is fully statically type
checked and supposedly type safe, also has this problem.
My original message was sent only to Larry to inform him of the problem as
Cleanup Chair. I did not intend to have it redistributed, because X3J has
enough on its hands right now, and one could make a legitimate argument
that, since typing is "optional" in Common Lisp anyway, the problem was
not particularly serious. However, now that the issue has been broached,
we might as well discuss it.
jak