<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    > So it makes no sense to create an instance of COUNTED-CLASS
    which inherits from RECTANGLE.<br>
    <br>
    Sure it does. Any given class metaobject has two kinds of
    relationships with other class metaobjects: It has an INSTANCE-OF
    relationship with its metaclass and an ISA (or INHERITANCE)
    relationship with its superclasses.<br>
    <br>
    The equivalent (and more conventional) definition of <font
      face="monospace">counted-rectangle</font> would be<br>
    <font face="monospace"><br>
      (defclass counted-rectangle (rectangle)<br>
        ()<br>
        (:metaclass counted-class))</font><br>
    <br>
    and this makes perfect sense.<br>
    <br>
    What doesn't work in the example is that <font face="monospace">rectangle</font>
    and <font face="monospace">counted-rectangle</font> have different
    metaclasses. Any time class A inherits from class B, they both
    should be instances of the same metaclass. This is the piece of the
    puzzle that AMOP gets wrong because the book was written before this
    rule* was established. It's also the reason I dislike using special
    metaclasses: The semantics of two classes that are instances of
    different metaclasses inheriting from one another are ... not
    well-defined. That means every time you use a special metaclass you
    have to define all your classes in that hierarchy with the
    :metaclass argument.<br>
    <blockquote>*It's more a convention than a rule. It makes
      implementors' lives much easier knowing that two inheriting class
      metaobjects are of the same metaclass. One could fix this problem
      with a <font face="monospace">validate-superclass</font> method
      but whether the resulting class metaobject would actually work is
      implementation-specific:<br>
      <br>
      <font face="monospace">(defmethod validate-superclass ((class
        counted-class) (superclass standard-class))</font><br>
      <font face="monospace">  t)</font><br>
      <br>
      That works on Lispworks but not CCL or SBCL, because they're both
      buggy about how and where they call <font face="monospace">validate-superclass</font>
      (see below). This is not the best solution. Here be dragons.<br>
    </blockquote>
    <br>
    The best solution which works reliably for all implementations is to
    redefine rectangle as:<br>
    <br>
    <font face="monospace">(defclass rectangle ()<br>
          ((height :initform 0.0 :initarg :height)<br>
           (width :initform 0.0 :initarg :width))<br>
          (:metaclass counted-class))</font><br>
    <br>
    <b>But</b> even this is not enough, because there's a subtle bug the
    way CCL and SBCL call <font face="monospace">validate-superclass</font>.
    The above definition of <font face="monospace">rectangle</font>
    throws an error:<br>
    <font face="monospace">> Error: The class #<STANDARD-CLASS
      STANDARD-OBJECT> was specified as a<br>
      >        super-class of the class #<COUNTED-CLASS
      RECTANGLE>;<br>
      >        but the meta-classes #<STANDARD-CLASS
      STANDARD-CLASS> and<br>
      >        #<STANDARD-CLASS COUNTED-CLASS> are
      incompatible.<br>
      > While executing: #<a class="moz-txt-link-rfc2396E" href="CCL::STANDARD-KERNEL-METHODCCL::ENSURE-CLASS-INITIALIZED(CCL::SLOTS-CLASS)"><CCL::STANDARD-KERNEL-METHOD
      CCL::ENSURE-CLASS-INITIALIZED (CCL::SLOTS-CLASS)></a>, in process
      Listener(4).<br>
    </font><br>
    This error is ridiculous (and a bug) because <font face="monospace">STANDARD-OBJECT</font>
    is already a superclass of every CLOS instance (including class
    metaobjects). This bug occurs in both CCL and SBCL but not
    Lispworks.<br>
    <br>
    The fix is to define<br>
    <br>
    <font face="monospace">(defmethod <a class="moz-txt-link-freetext" href="ccl::validate-superclass">ccl::validate-superclass</a> ((c1
      standard-class) (c2 standard-object))<br>
        t)</font><br>
    <br>
    [This is not the absolute best way to fix the problem but it works.
    The real fix is to ensure that CCL and SBCL only call <font
      face="monospace">validate-superclass</font> after the class
    metaobjects in question are initialized enough that they know what
    they are instances <i>of</i>, and also figure out why this error
    only happens on special metaclasses. I'll leave that for another
    day.]<br>
    <br>
    So a complete solution--using the unorthodox definition style of the
    AMOP example--is as follows:<br>
    <br>
    <font face="monospace">#+CCL<br>
      (defmethod <a class="moz-txt-link-freetext" href="ccl:validate-superclass">ccl:validate-superclass</a> ((c1 standard-class) (c2
      standard-object))<br>
        "Must define this anytime you're using special metaclasses in
      CCL."<br>
        t)<br>
      <br>
      #+SBCL<br>
      (defmethod sb-mop:validate-superclass ((c1 standard-class) (c2
      standard-object))<br>
        "Must define this anytime you're using special metaclasses in
      SBCL."<br>
        t)<br>
      <br>
      (defclass counted-class (standard-class)<br>
         ((counter :initform 0)))<br>
      <br>
      (defclass rectangle ()<br>
          ((height :initform 0.0 :initarg :height)<br>
           (width :initform 0.0 :initarg :width))<br>
          (:metaclass counted-class))<br>
      <br>
      ; A goofy way to define a class, but it demonstrates dynamic class
      creation<br>
      (setf (find-class 'counted-rectangle)<br>
             (make-instance 'counted-class<br>
               :name 'counted-rectangle<br>
               :direct-superclasses (list (find-class 'rectangle))<br>
               :direct-slots ()))<br>
    </font><br>
    One more comment: This is a bad example on the part of AMOP but for
    a different reason than Ron described. If you really want a
    counted-class, using a class-allocated slot is a much better
    approach. That way you don't need all this metaclass nonsense.<br>
    <br>
    -SS<font face="monospace"><br>
      <br>
      <br>
    </font>On 3/4/21 3:31 PM, Ron Garret wrote:<br>
    <blockquote type="cite"
      cite="mid:AC81379F-82CE-4C90-995D-FF1729A8B2DE@flownet.com">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      The first thing to do is to see if a different CL implementation
      gives the same error:
      <div><br>
      </div>
      <div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">➔
          sbcl</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">This
          is SBCL 1.1.9, an implementation of ANSI Common Lisp.</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">More
          information about SBCL is available at <<a
            href="http://www.sbcl.org/" moz-do-not-send="true">http://www.sbcl.org/</a>>.</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;
          min-height: 14px;"><br>
        </div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">SBCL
          is free software, provided as is, with absolutely no warranty.</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">It
          is mostly in the public domain; some portions are provided
          under</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">BSD-style
          licenses.  See the CREDITS and COPYING files in the</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">distribution
          for more information.</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">(defclass
          rectangle ()</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">  
          ((height :initform 0.0 :initarg :height)</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;"> 
            (width :initform 0.0 :initarg :width)))</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;
          min-height: 14px;"><br>
        </div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">#<STANDARD-CLASS
          RECTANGLE></div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">(defclass
          counted-class (standard-class)</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">  
          ((counter :initform 0)))</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;
          min-height: 14px;"><br>
        </div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">#<STANDARD-CLASS
          COUNTED-CLASS></div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">(make-instance
          'counted-class</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">  
                :name 'counted-rectangle</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">  
                :direct-superclasses (list (find-class 'rectangle))</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">  
                :direct-slots ())</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;
          min-height: 14px;"><br>
        </div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;">debugger
          invoked on a SIMPLE-ERROR:</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;"> 
          The class #<STANDARD-CLASS RECTANGLE> was specified as a
          super-class of the</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;"> 
          class #<COUNTED-CLASS COUNTED-RECTANGLE>, but the
          meta-classes</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;"> 
          #<STANDARD-CLASS STANDARD-CLASS> and #<STANDARD-CLASS
          COUNTED-CLASS> are</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;"> 
          incompatible.  Define a method for SB-MOP:VALIDATE-SUPERCLASS
          to avoid this</div>
        <div style="margin: 0px; font-size: 10px; font-family: Monaco;"> 
          error.</div>
      </div>
      <div><br>
      </div>
      <div>So this appears to be a bug in the MOP book.  And, if you
        think about it, the example in the book really doesn’t make
        sense.  COUNTED-CLASS is a metaclass, i.e. all of its instances
        are classes.  But RECTANGLE is not a meta-class, it is a class.
         All of its instances are rectangles, which are not classes.  So
        it makes no sense to create an instance of COUNTED-CLASS which
        inherits from RECTANGLE.  The instances of such a class would
        have to be both classes and rectangles, and that’s not possible.</div>
      <div><br>
      </div>
      <div>rg</div>
      <div><br>
        <div>
          <div>On Mar 4, 2021, at 2:07 PM, Paul Krueger <<a
              href="mailto:plkrueger@comcast.net" moz-do-not-send="true">plkrueger@comcast.net</a>>
            wrote:</div>
          <br class="Apple-interchange-newline">
          <blockquote type="cite">
            <meta http-equiv="Content-Type" content="text/html;
              charset=UTF-8">
            <div style="word-wrap: break-word; -webkit-nbsp-mode: space;
              line-break: after-white-space;" class=""><span
                style="font-family: Monaco; font-size: 12px;" class="">I
                was trying to do a little MOP hacking and when what I
                was trying to do got errors I went back to “The Art of
                the Metaobject Protocol” and ran an example from there
                to see if it encountered similar errors, which it did
                (most of this from p. 72 of the book):</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <br style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">I’m running Clozure Common Lisp Version 1.11.6
                (v1.11.6) DarwinX8664</span><br style="font-family:
                Monaco; font-size: 12px;" class="">
              <br style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">? (defclass rectangle ()</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">   ((height :initform 0.0 :initarg :height)</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">    (width :initform 0.0 :initarg :width)))</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">#<STANDARD-CLASS RECTANGLE></span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">? (defclass counted-class (standard-class)</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">   ((counter :initform 0)))</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">#<STANDARD-CLASS COUNTED-CLASS></span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">? (setf (find-class 'counted-rectangle)</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">       (make-instance 'counted-class</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">         :name 'counted-rectangle</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">         :direct-superclasses (list (find-class
                'rectangle))</span><br style="font-family: Monaco;
                font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">         :direct-slots ()))</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <blockquote type="cite" style="font-family: Monaco;
                font-size: 12px;" class="">Error: The class
                #<STANDARD-CLASS RECTANGLE> was specified as a<br
                  class="">
                      super-class of the class #<COUNTED-CLASS
                COUNTED-RECTANGLE>;<br class="">
                      but the meta-classes #<STANDARD-CLASS
                STANDARD-CLASS> and<br class="">
                      #<STANDARD-CLASS COUNTED-CLASS> are
                incompatible.<br class="">
                While executing: #<a class="moz-txt-link-rfc2396E" href="CCL::STANDARD-KERNEL-METHODCCL::ENSURE-CLASS-INITIALIZED(CCL::SLOTS-CLASS)"><CCL::STANDARD-KERNEL-METHOD
                CCL::ENSURE-CLASS-INITIALIZED (CCL::SLOTS-CLASS)></a>, in
                process Listener(4).<br class="">
                Type cmd-. to abort, cmd-\ for a list of available
                restarts.<br class="">
                Type :? for other options.<br class="">
              </blockquote>
              <span style="font-family: Monaco; font-size: 12px;"
                class="">1 > </span><br style="font-family: Monaco;
                font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">?</span><br style="font-family: Monaco;
                font-size: 12px;" class="">
              <br style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">My question is whether this is a problem with
                CCL’s implementation or a spec change of some sort that
                invalidates the example from the book. It’s not clear to
                me how you could ever employ meta-classes without
                getting this sort of error in CCL, so if this isn’t a
                bug, what’s the work-around?</span><br
                style="font-family: Monaco; font-size: 12px;" class="">
              <br style="font-family: Monaco; font-size: 12px;" class="">
              <span style="font-family: Monaco; font-size: 12px;"
                class="">Thanks ...</span></div>
            _______________________________________________<br>
            Openmcl-devel mailing list<br>
            <a href="mailto:Openmcl-devel@clozure.com"
              moz-do-not-send="true">Openmcl-devel@clozure.com</a><br>
            <a class="moz-txt-link-freetext" href="https://lists.clozure.com/mailman/listinfo/openmcl-devel">https://lists.clozure.com/mailman/listinfo/openmcl-devel</a><br>
          </blockquote>
        </div>
        <br>
      </div>
      <br>
      <fieldset class="mimeAttachmentHeader"></fieldset>
      <pre class="moz-quote-pre" wrap="">_______________________________________________
Openmcl-devel mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Openmcl-devel@clozure.com">Openmcl-devel@clozure.com</a>
<a class="moz-txt-link-freetext" href="https://lists.clozure.com/mailman/listinfo/openmcl-devel">https://lists.clozure.com/mailman/listinfo/openmcl-devel</a>
</pre>
    </blockquote>
    <br>
  </body>
</html>