[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [spr8565] Is this a bug or not?
[This matter has been assigned the tracking identifier "spr8565".
Please refer to it in any followup communication. Also, be sure
to cc email@example.com so that if I am unavailable someone else will
be able to respond.]
From: firstname.lastname@example.org (Lothar Hotz)
To: bugs@Franz.COM, email@example.com
Subject: Is this a bug or not?
(defclass meta1 (standard-class) ())
in one file, and compile and load this file.
(defclass my-metaclass (meta1)
(defclass my-class () () (:metaclass my-metaclass))
in another file (say meta-error.lisp),
compiling this file leads to:
USER(395): (compile-file "meta-error.lisp")
; --- Compiling file /users/lothar/prokon/konwerk-obk/meta-error.lisp ---
; While compiling (:TOP-LEVEL-FORM "meta-error.lisp" 2):
Error: While computing the class precedence list of the class named META1.
The class named META1 is a forward referenced class.
The class named META1 is a direct superclass of the class named META1.
[condition type: PROGRAM-ERROR]
Having all definitions in one file,
or separating the definition of my-class in another file,
or simply loading the file meta-error.lisp
lead to the desired behaviour (i.e. defining the classes without an error).
The problem might occure because meta1 is not known in the compiler
environment, there for a forward referenced class is created...?
Are there any other solutions as separating definitions in files?
I've been giving this question some thought. I think the issue itself
is a lot clearer than what the language standards say about it.
It you look through CLtL2, there is no explicit discussion whether a
class defined during a file compilation may be used as the :METACLASS
for a DEFCLASS in the same file. However, the explicit requirements
on COMPILER-FILE procesing of a DEFCLASS at top level of a file (CLtL2
p.690) -- only that the class name may be used in the same file as a
DEFMETHOD specializer and in type declarations -- suggest that use in
:METACLASS is not portable.
In addition, one can make a good argument why such a guarantee would
impose impossible problems on the MOP. Since the MOP needs to operate
using class objects, and since the MOP needs to operate at
compile-file time (at least if expected optimizations are to be
possible), then an instance of the metaclass must be created at
compile-file time. But in general the appearance of a DEFCLASS at
compile-file time does _not_ make that class instantiable at compile
time, so it's hard to see how a DEFCLASS can be used subsequently in
the same file as a metaclass. The fact that it works in _some_ simple
test cases is in part accidental; certainly you can't in a single file
write any _methods_ on the metaclass and expect them to operate at
compile time, and the existence of specialized methods is the usual
reason for defining your own metaclass.
Unfortunately, if you accept this line of reasoning, we still need to
contend with the draft ANSI spec. I was quite surprised to notice
that it adds the requirement (dpANS p.7-65): "[The] compiler must make
this class name ... be recognized as a valid class name ... for use as
the :metaclass option of a subsequent defclass."
(This statement is actually pretty vague as it stands. Any symbol
that isn't exported from the COMMON-LISP package is a "valid" class
name, at least syntacically, so presumably the intention here of
"valid" is that the usage won't signal error. But that requires that
the metaclass must be instantiable, and this requirement isn't placed
on any other defclass forms. What's worse, the fact that a defclass
will be used as a metaclass isn't even discernable from the defclass
itself; it only becomes evident when the defclass that uses it is
I'm a member of X3J13, and I don't remember this change ever being
considered by the committee. I suspect it was an innocent editorial
cleanup that wasn't carefully considered for its implications. I'm
asking around X3J13 to figure out how this happened, and I'll probably
try to get it removed.