Recently, I was playing with the CLIM-LISTENER (thanks to Paolo's suggestion that it would provide good exercise for the graph-rendering code), and found that it often crashed under Allegro CL, with MOP errors.
I'm no MOP authority, so I dropped a line to Franz to ask them why this was happening. Steve Haflich kindly filled me in on why, and offered some comments on the use of the MOP to interrogate the class hierarchy in the CLIM listener. With his permission, here's some of what he said:
From: rpgoldman@sift.info
I have been trying to use a portable class browser for class hierarchies with ACL 6.2, and have been getting frequent errors like this:
CL-USER(8): (aclmop:class-slots (find-class 'clim::application-frame)) Error: Class #<STANDARD-CLASS CLIM:APPLICATION-FRAME> is not yet finalized. [condition type: PROGRAM-ERROR]
Restart actions (select using :continue): 0: Return to Top Level (an "abort" restart). 1: Abort entirely from this process. [1] CL-USER(9):
[note: this is with the open McCLIM clim implementation, not ACL CLIM.]
I'm confused by this error, since it seems to contradict the documentation I have, which states:
"Class finalization is the process of computing the information a class inherits from its superclasses and preparing to actually allocate instances of the class. ...
To support forward-referenced superclasses, and to account for the fact that not all classes are actually instantiated, class finalization is not done as part of the initialization of the class metaobject. Instead, finalization is done as a separate protocol, invoked by calling the generic function finalize-inheritance. The exact point at which finalize-inheritance is called depends on the class of the class metaobject; for standard-class it is called sometime after all the classes superclasses are defined, but no later than when the first instance of the class is allocated (by allocate-instance)."
But I have an instance of this class that the MOP seems to be telling me is not finalized:
GRAPH-MDP(77): (class-of *frame*) #<STANDARD-CLASS TAEMS-MDP-APP> GRAPH-MDP(78): (aclmop:class-direct-superclasses (class-of *frame*)) (#<STANDARD-CLASS STANDARD-APPLICATION-FRAME>) (aclmop:class-direct-superclasses (first (aclmop:class-direct-superclasses (class-of *frame*)))) (#<STANDARD-CLASS APPLICATION-FRAME> #<STANDARD-CLASS CLIM-INTERNALS::PRESENTATION-HISTORY-MIXIN>)
Based on the above, shouldn't APPLICATION-FRAME have been finalized? Or is it not finalized because it doesn't have any DIRECT instances?
SMH> Your suggested analysis is correct: A class is only required to be SMH> finalized when it is directly instantiated. (See the term "direct SMH> instance" in the ANS Glossary.) There is no need to finialize SMH> superclasses. In fact, there is good reason not to do so, even beyond SMH> the fact that it is a waste of time and storage:
SMH> If one has a collection of mixin classes, sometimes the oeration of SMH> one mixin might depend on functionality, perhaps a method, provided by SMH> a different mixin. If one instantiates a class that doesn't have a SMH> complete set of these interrelated mixins, an error can be signalled SMH> at execution time. It is sometime done that a mixin will implement SMH> checking for other necessary classes and/or method. It can do this in SMH> various ways, such as by defining :after methods on SMH> finalize-inheritance. The idea is that it is much better to signal SMH> error for some inconsistency earlier rather than later.
Steve went on to directly comment on the class browsing in CLIM-LISTENER:
SMH> .... We agreed in the last round that a class does not _have_ a SMH> class-slots property until it is finalized, and not all classes are SMH> always finalized. Further, it's even worse, because some classes SMH> cannot even be finalized. As I suggested before, a mixin class might SMH> have code to guarantee it is not finalized (or instantiated) unless SMH> certain conditions are met. And of course finalization is impossible SMH> if a class' superclasses include a forward-reference-class.
SMH> So ideas like trying to force all classes to be finalized or to SMH> trigger class finalization when inspected probably aren't good ones.
SMH> I don't know if it is possible for you to suggest McCLIM be fixed SMH> (which would be best) or whether you have to try to patch this locally SMH> in your copy. But you might investigate what the McCLIM inspector SMH> itself does in the situation that a class still has forward SMH> references.
SMH> class-slots is defined to return a list of SMH> effective-slot-definition-objects, which cannot exist until SMH> finalization. Depending on the needs of the browser, it is SMH> straightforward to write a class walker that computes a partial list SMH> of known slots by walking the portions of the superclass tree that are SMH> defined (i.e. stopping on forward-reference-classes). But that would SMH> compute a set of direct-slot-definition-objects (possibly multiple SMH> dsd's per slot) instead of esd's, so the browser would need to be SMH> modified to accept this.
As I said, I'm no expert on the MOP, or the internals of the CLIM-LISTENER, so I'm not sure how feasible/desirable such a rewrite would be. For that matter, I'm not sure why the CLIM-LISTENER works on CMUCL and SBCL...
I'd be willing to rally round to help fix this if anyone wants to take charge, especially to conduct tests on ACL 6.2 and 7.0. But I'm not qualified to be more than a foot-soldier in that effort....
Cheers, R