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

comments on some standard type classes



    Date: 22 Oct 87 16:21 PDT
    From: Danny Bobrow <Bobrow.pa@Xerox.COM>

     Moon:
       1-17 I still think it's wrong for list to be more specific than
	symbol in the CPL of null.  Consider the print-object methods. 
	Also consider the introjection of symbol between list and sequence,
	a surprising CPL.

    I understand the first point.  This comes to the point of whether one
    wants to print NIL
     as ()
     or NIL
    I don't understand the second point.  What do you mean by introjection
    here?  Show the surprise please (not that I wasn't surprised --- I just
    couldn't open the box). 

The natural direct superclasses of null are list and symbol, in some
order.  The CPL of list is (list sequence t), of symbol is (symbol t).
What surprised me was to see the CPL of null be (null list symbol
sequence t), which has symbol inserted in the middle of list's CPL.
Usually one expects to see non-intersecting superclass trees kept
disjoint in the CPL, thus I would have expected to see (null symbol list
sequence t) or at worst (null list sequence symbol t).  The only way to
get (null list symbol sequence t) from the standard CPL algorithm is if
sequence is a direct superclass of null.

    Date: 22 Oct 87 15:32 PDT
    From: Danny Bobrow <Bobrow.pa@Xerox.COM>

    The motivating example for this was something like:
 
    (defmethod  some-mapper ((x listp) fn)
	 (when x (funcall fn (car x)) (some-mapper (cdr x) fn))

    (defmethod some-mapper ((x symbolp) fn)
	 (some-mapper (look-up-in-table x *table*) fn)

    Here one wants the recursion to NIL to be handled in the listp case
    without having to think about the method on symbolp.  

I guess.  It's actually a bit strange that the list method thinks it's
really important to be called for both empty and non-empty lists, but
the first thing it does is to split into two disjoint code sequences,
one for empty lists and the other for non-empty lists.  It makes me
wonder why you didn't write

(defmethod some-mapper ((x list) fn)
  (funcall fn (car x))
  (some-mapper (cdr x) fn))

(defmethod some-mapper ((x null) fn)
  (declare (ignore fn))
  nil)

I think what you are really objecting to is that there is no class name
for the subclass of SYMBOL that includes all symbols other than NIL.
The Common Lisp type system doesn't need a name for that, because you
can say (and symbol (not null)), but CLOS doesn't allow that as a
parameter specializer name.

Of course if your first method had been

(defmethod some-mapper ((x sequence) fn)
  (map nil fn x))

it would not have worked, with the CPL as currently in the document.
That's another way of making my "introjection" point.

    What is an example in which one would want this another way.  

Well, there's the one I already mentioned:

;; Simplified to ignore *print-escape*, *print-case*
(defmethod print-object ((x symbol) stream)
  (maybe-print-package-prefix x stream)
  (write-string (symbol-name symbol) stream))

;; Simplified to ignore *print-length*, *print-pretty*
(defmethod print-object ((x list) stream)
  (do ((c #\( #\space))
      ((atom x))
    (write-char c stream)
    (print-object (pop x) stream))
  (when x
    (write-string " . " stream)
    (print-object x stream))
  (write-char #\) stream))

Here we want the symbol method when x is NIL.

Now of course you're going to tell me that CLOS does have a class name
for the subclass of LIST that includes all lists other than (), and
therefore it's easier to fix my example to conform to your CPL than it
is to fix your example to conform to my CPL.  While that's true, it
seems like backwards reasoning somehow.

I guess I can accept (null list sequence symbol t) as the CPL, although
I still think (null symbol list sequence t) fits the rest of the language
a little better.  Maybe that's because all the built-in symbol functions
work for nil, but only some of the built-in list functions work for nil.
Maybe I'm just confused in thinking that rplaca is a list function rather
than a cons function.  Or, in other words, you should almost never put
a method on LIST, because that class is too general; put it on CONS instead.

					       I think we should in this
    case be driven by some examples, since this pun in Lisp is
    atheoretic.(NIL is the same as empty list) 

Agreed, in Common Lisp NIL is always a headache one way or another.
I'm sure we can find any number of examples in support of each of the
possible CPLs, so examples may not help much to reach a decision.

Oh by the way, while I have your attention, what about the other potential
standard-type classes: function, hash-table, package, pathname,
random-state, readtable, and stream.  I think these are awaiting
cleanup action to straighten out the subtype and disjointness relations
of these in the CL type system before CLOS adopts them; should these
names be listed in our document?  The CL-Cleanup issue FUNCTION-TYPE
should take care of the first of these; the rest depend on
PATHNAME-HASH-TABLE-TYPE-DISTINCT, which seems to have dropped through
the cracks, unless that's just the extreme imperfection of my personal
records.

 From June 10:

4. ISSUE: PATHNAME-HASH-TABLE-TYPE-DISTINCT
   Mandating a bunch of types (I don't have the complete list right now)
   to be disjoint from a bunch of other types (again I don't have a
   complete list right now) so that they can all be made into classes
   without establishing any implementation-dependent subclass relationships.
   [the types STREAM, PACKAGE, PATHNAME,  READTABLE and RANDOM-STATE can be
    required to be disjoint from other types (e.g., as if they had been created
    with DEFSTRUCT.)
    I don't think we currently require structures to be a disjoint
    type from vectors, etc., though this has been talked about.  So that
    should be part of any proposal. --Fahlman ]