[Openmcl-devel] (SETF FIND-CLASS)

Gary Byers gb at clozure.com
Wed May 6 04:29:52 PDT 2009

On Wed, 6 May 2009, Leslie P. Polzer wrote:

> Gary Byers wrote:
>> There's a (possibly slightly faster) way of determining that a symbol
>> is a type specifier that (properly) names a class.  (If it's any faster,
>> that'd be because CLASS-NAME is a generic function.)
>> Figuring that out (in general, mapping from a type specifier to a
>> class or some other representation of a type) as quickly as possible
>> is important for things like TYPEP and SUBTYPEP (when they couldn't do
>> that simplification at compile-time), but we're talking about the
>> expansion of DEFTYPE (CCL::%DEFTYPE) here ...  That usually happens at
>> load time and isn't much of a bottleneck, so the straightforward check
>> for proper-namedness is fine here.
> CCL already has proper name handling (not in DEFTYPE though), but I
> think it might be flawed.

I wasn't even thinking of that, just changing the:

((and *type-system-initialized*
               (or (built-in-type-p name) (find-class name nil)))
          (error "Cannot redefine type ~S" name))

clause in CCL::%DEFTYPE to:

((and *type-system-initialized*
               (or (built-in-type-p name)
                   (let* ((c (find-class name nil)))
                     (and c (eq name (class-name c))))))
          (error "Cannot redefine type ~S" name))

> CLHS's definition of a proper name:
>  If S is a symbol such that S = (class-name C) and C = (find-class S),
>  then S is the proper name of C.
> So since CLASS-NAME is redefinable by the user there's no way
> to circumvent the check against it (except if we were to watch
> and record any redefinition of it, obviously).

The function (SETF CLASS-NAME) happens to be implemented as a generic
function in CCL; there's one method, specialized on the classes T and CLASS.

The primary method on (SETF CLASS-NAME) uses (SETF CCL::%CLASS-PROPER-NAME)
to update the internal proper-name slot.  (It's defined around line 1700
in "ccl/level-1/l1-clos.lisp".)  That method also worries about whether
the name's status as a type specifier changes and whether that conflicts
with type specifiers defined with DEFTYPE.

User code can certainly call (SETF CLASS-NAME) to change a class's name
at any time, and doing so affects whether or not the class is properly
named.  As far as I know, the cached proper-name slot is maintained

I'm not sure that I believe that users can portably redefine what
(SETF CLASS-NAME) does, though since it's a generic function in CCL
they can probably define methods that're specialized to metaclasses
that they've defined (unless/until (SETF CLASS-NAME) changes into
a non-generic function.)  If someone defined such a method, I'm not
sure that I'm too concerned about what'd happen if they neglected
to call the primary method.

CLASS-NAME can more plausibly be redefined by the user, but (SETF
CLASS-NAME) doesn't need to know anything about how CLASS-NAME
is implemented: it just does (REINITIALIZE-INSTANCE class :NAME name).
The MOP says that CLASS-NAME returns the defaulted value of the
:NAME initarg; it doesn't say what happens if it returns something
else, or if it's non-deterministic:

(defmethod class-name ((c my-metaclass))
   (case (day-of-week)

and, to be honest, it hurts my head just to think about that ...

So, I think that it's fairly safe to predict that (SETF (CLASS-NAME
CLASS) NAME) will cause subsequent calls to (CLASS-NAME CLASS) to
return NAME, and to exploit that to cache info about the class's
proper name.

(The whole point of maintaining that cached info is, IIRC, to
speed up some cases of TYPE-OF, which are supposed to return a
class name if the argument's class is properly named and the
class itself otherwise; an application that made heavy use of
the idiom:

;;; It's possible that (TYPEP X 'FOO) was intended in many cases,
;;; but it's not exactly the same thing and hard to know.
   (eq (type-of x) 'foo)

was spending a lot of time in FIND-CLASS and CLASS-NAME, and
the cached internal PROPER-NAME slot eliminated that overhead.)

> But the current proper name framework (%class-proper-name,
> update-class-proper-names) does not honor this relationship
> and just manages the proper name via FIND-CLASS and its setter,
> storing it in an internal class slot.
> We should probably first get rid of the current code
> and replace it with something like this:
>  (defun %proper-name (class)
>    "Return the proper name of a class or NIL if there's no proper name."
>    (let ((name (class-name class)))
>      (when (eq (find-class name nil) name)
>        name)))
>  (defun %proper-name-p (name class)
>    (and class (eq name (%proper-name class))))
> Later we can think about a caching mechanism for this if it
> turns out to be important.

It is important (in some contexts), and AFAIK the cached info is
maintained correctly.

>  Leslie
> -- 
> http://www.linkedin.com/in/polzer
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel

More information about the Openmcl-devel mailing list