Class validation: how to avoid creating dummy instances?

I had a problem with the fact that the third-party library should act in the class, as if it were complete. After some reading, I understand the motivation for this mechanism, but I really don't know how it works.

Example:

(make-instance 'expression :op '+ :left 'nan :right 'nan) (defmethod normalize-expression ((this expression)) (optima:match this ((optima::or (expression :left 'nan) (expression :right 'nan)) 'nan) ((expression :op op :left x :right y) (funcall op xy)))) 

If I do not add the first line, the function will not compile, which will give me this error:

 ; caught ERROR: ; (during macroexpansion of (SB-PCL::%DEFMETHOD-EXPANDER NORMALIZE-EXPRESSION ...)) ; SB-MOP:CLASS-SLOTS called on #<STANDARD-CLASS EXPRESSION>, which is not yet finalized. ; See also: ; AMOP, Generic Function SB-MOP:CLASS-SLOTS 

optima is a pattern matching library, (expression :op op ...) matches instances of the expression class by this pattern. I don’t know much details, but it looks like he should know what accessors are for this class, and it looks like this information is not available until it is complete. So, is there a way around the finalization problem?

The class will not be extended (at least not in this project, and it is not planned). It doesn't hurt to create a dummy instance ... it's just an ugly solution, so I was hoping to find the best. In addition, perhaps I will get additional information about the completion, which is also good :)

+4
source share
1 answer

Forgetting to ensure class completion seems to be a fairly common mistake when using MOP.

In lisp, classes are defined in two β€œphases”:

  • Direct class definition
  • Effective Class Definition

The definition of a direct class is isomorphic to the defclass form. It has a class name, superclass names, a list of direct slots (i.e., Slots defined on this particular class, but on its superclasses).

An effective class definition contains all the information needed by the compiler / interpreter. It contains a list of all the slots of the class (including those defined on superclasses), a mock instance of the class, links to access methods, etc.

The process of converting a direct definition of a class to an effective definition of a class is called class termination. Because CLOS supports class overrides, final refinement can be called several times for a class. One of the reasons that completion is delayed is that a class can be defined before its superclasses are defined.

As for your specific problem: it seems that optima:match should make sure the class is finalized before trying to list its slots. This can be done with two functions: class-finalized-p (to check if class completion is required) and finalize-inheritance to actually do the finalization. Or you can use the closer-mop:ensure-finalized utility function. (close-mop is a library for portable use of CLOS MOP).

eg,:.

 (c2mop:ensure-finalized (find-class 'expression)) 
+7
source

Source: https://habr.com/ru/post/1494147/


All Articles