[pro] Modularity for subclassing in Common Lisp

Pascal Costanza pc at p-cos.net
Tue Dec 7 18:58:40 UTC 2010


On 1 Dec 2010, at 21:16, Daniel Weinreb wrote:

> I have always liked the idea of having protocols
> say more than just "these are the functions
> and these are the arguments, which are optional,
> ane maybe what their types are.  I'd love it
> if there were a way to say "in order to fulfill
> this contract, doing write-string of a string
> must behave exactly the same as doing
> write-char on each."  You could imagine all
> kinds of integrity constratints.  You could
> specify that some function be commutative,
> that some be associative with respect to
> each other, that one have no side effects, that
> one be idempotent, and so on.  We could
> start by having a well-known template
> for documenting/commenting the functions
> in a protocol to be able to say things like this.


I would also like to specify that methods on a specific generic function should always halt, and would like to enforce that statically. ;-)

I'm only half joking: The fact that you cannot solve the halting problems puts some boundaries on what you may and may not be able to express in such contracts. On top of that, it is extremely hard to be precise enough when specifying such contracts.

Let's take your example "write-string must behave exactly the same as doing write-char on each". Let's assume these functions are implemented as follows for the default case:

(shadow 'write-char)
(shadow 'write-string)

(defgeneric write-char (stream char)
   (:method ((stream t) (char char))
     (cl:write-char char stream)))

(defgeneric write-string (stream string)
  (:method ((stream t) (string string))
    (loop for char across string do
      (write-char stream char))))

Now assume somebody implements their own stream class and does the following:

(defmethod write-char ((stream my-stream) (char char))
  (write-string stream (make-string 1 :initial-element char)))

(defmethod write-string ((stream my-stream) (string string))
  (cl:write-string string stream))

This breaks your suggested contract. Why? Somebody else may want to provide some form of mixin functionality like this:

(defmethod write-char :around (stream char)
  (incf *write-counter*)
  (call-next-method))

With the original methods, this correctly counts he written characters, but with the methods for my-stream, most characters will not be counted anymore. Your suggested contract seems to suggest that this :around method is correct and the methods for my-stream break the contract. Is that what you intended?


Pascal

-- 
Pascal Costanza, mailto:pc at p-cos.net, http://p-cos.net
Vrije Universiteit Brussel
Software Languages Lab
Pleinlaan 2, B-1050 Brussel, Belgium










More information about the pro mailing list