[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Is it possible to use deftyped types as parameter-specializers?



    Date: Wed, 15 Mar 89 14:00:13 PST
    From: Darrell <shane%blackcomb@rand.org>

    Consider the following:

    (deftype symbol-or-string () '(or symbol string))
    (deftype non-nil-symbol-or-string () '(satisfies non-nil-symbol-or-string))
    (defun non-nil-symbol-or-string (x) 
      (if (and (typep x 'symbol-or-string) (not (null x))) t nil))

    Suppose I wanted a method to be applicable only when its argument is of 
    type non-nil-symbol-or-string.  If non-nil-symbol-or-string were a class 
    then the method I want would look like:
	    (defmethod meth ((arg non-nil-symbol-or-string))
	      (format t "~A is a non-nil symbol or a string.~%" arg))

    Is this possible in clos?

This is not possible in CLOS.  The only permissible parameter
specializers are classes and lists of the form (EQL <object>).

This question comes up fairly regularly, it is something people always
wonder about.  The spec doesn't explain the reasoning behind this, I
believe Sonya Keene's book does.  Here is an explanation which should
help:

The reason is that, in CLOS, a generic function must be able to order
the set of applicable methods.  That is, once the set of methods that
can be applied to the arguments are determined, those methods must be
ordered in terms of specificity.  The entire determination of method
combination and which method to apply is based on being able to perform
this ordering.

Using specializers like the one you propose break the ability to do this
ordering.  To see this, suppose I tried to make what you are suggesting
work and wrote the following:

 (deftype symbol-or-string () '(or symbol string))
 (deftype string-or-number () '(or string number))

 (defmethod trouble ((x symbol-or-string)) 'symbol-or-string)
 (defmethod trouble ((x string-or-number)) 'string-or-number)

If I say (trouble 'foo) things are OK.  Also, (trouble 32) is OK.  But,
if I say (trouble "what now?") I have no sound mechanism for determining
which of the two applicable methods is more specific.

It is true that there are any number of rules we could come up with for
ordering these methods.  It is possible that some of these rules are
reasonable for a given application.  But it doesn't seem possible to
discover a rule that will be reasonable for all uses.

If you really want to do this, there is the metaobject protocol.  It
will let you define a generic function of your own that follows the
lookup rules you want.
-------