<html><head></head><body bgcolor="#FFFFFF"><div>wow, this is a really helpful example as I have recently been stumbling about the problem of introducing a persistent subclass of layered-class (specifically on top of the dstm transactional layered class example that I found floating around and the associated paper by pascal.)   Is this something that might be valuable to annotate a bit and include in the contextl distro as an additional example?  </div>
<div><br></div><div>contextl seems to be the answer to a number of questions regarding how to combine meta class behaviors, but the biggest problem I have run into is the sparseness of the papers and examples with regards to learning how to model solutions based on layered class architectures.  This seems like a useful addition?<br>
<br></div><blockquote type="cite"><div><font class="Apple-style-span" color="#000000"><br></font><span></span><br><span>Message: 1</span><br><span>Date: Sun, 18 Mar 2012 17:10:11 +0100</span><br><span>From: Pascal Costanza <<a href="mailto:pc@p-cos.net">pc@p-cos.net</a>></span><br>
<span>To: Paul Sexton <<a href="mailto:psexton.2a@gmail.com">psexton.2a@gmail.com</a>></span><br><span>Cc: <a href="mailto:closer-devel@common-lisp.net">closer-devel@common-lisp.net</a></span><br><span>Subject: Re: [closer-devel] ContextL: allow other keys in</span><br>
<span>    (re)initialize-instance methods for metaclasses</span><br><span>Message-ID: <<a href="mailto:4B1FC6C3-FAD1-4DAF-BA50-8AB687EE6259@p-cos.net">4B1FC6C3-FAD1-4DAF-BA50-8AB687EE6259@p-cos.net</a>></span><br><span>Content-Type: text/plain; charset=us-ascii</span><br>
<span></span><br><span>Hi Paul,</span><br><span></span><br><span>Thanks a lot again for reporting this problem. This uncovered a conceptual omission in the meta-level architecture of ContextL. Fortunately, it was easy to fix.</span><br>
<span></span><br><span>Background: Layered classes need to be split into a "base" class that gives identity to a particular layered class, plus all the partial definitions that belong to the various layers. The base class refers to the partial classes making up its definition by way of direct superclass links. All of this is set up in the partial-class metaclass. There needs to be a separation of initargs, some of which need to be routed to the base class (such as the name of the class, the defining metaclass and the direct superclass links), and the others need to go to the various partial definitions (such as direct slot definitions, for example).</span><br>
<span></span><br><span>The problem you uncovered was that this separation into base and partial initargs was hardcoded, and there was no way to configure this in one's own subclasses of partial-class and layered-class.</span><br>
<span></span><br><span>I have now introduced a generic function partial-class-base-initargs (with method combination 'append) on which methods can be defined that extend the initargs that need to go to the base class. Here is how it can be used to make the serializable layered class example work:</span><br>
<span></span><br><span>(in-package :contextl-user)</span><br><span></span><br><span>(defclass serializable-class (standard-class)</span><br><span>  ((database :initarg :database)))</span><br><span></span><br><span>(defclass combined-class (layered-class serializable-class) </span><br>
<span>  ())</span><br><span></span><br><span>(defmethod validate-superclass ((class combined-class) (superclass standard-class)) </span><br><span>  t)</span><br><span></span><br><span>(defmethod partial-class-base-initargs append ((class combined-class))</span><br>
<span>  '(:database))</span><br><span></span><br><span>(defclass try ()</span><br><span>  ()</span><br><span>  (:metaclass combined-class)</span><br><span>  (:database . "mydb"))</span><br><span></span><br><span>(finalize-inheritance (find-class 'try))</span><br>
<span></span><br><span>(assert (string= (slot-value (find-class 'try) 'database) "mydb"))</span><br><span></span><br><span>(assert (loop for class in (rest (class-precedence-list (find-class 'try)))</span><br>
<span>              never (slot-exists-p class 'database)))</span><br><span></span><br><span>This is now also part of the test suite for ContextL.</span><br><span></span><br><span>The changes are in the darcs repository for ContextL. Please let me know if this helps for your particular case, or if there are still missing problems.</span><br>
<span></span><br><span></span><br><span>Best,</span><br><span>Pascal</span><br><span></span><br><span>On 16 Mar 2012, at 01:32, Paul Sexton wrote:</span><br><span></span><br><blockquote type="cite"><span>Thanks -- I have figured out how to stop the error from occurring, but</span><br>
</blockquote><blockquote type="cite"><span>I now have a different problem: the initargs for classes other than</span><br></blockquote><blockquote type="cite"><span>layered-class seem to get ignored and do not result in values being</span><br>
</blockquote><blockquote type="cite"><span>stored in the class' slots.</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>Here is a simple example.</span><br></blockquote>
<blockquote type="cite"><span>---------------------</span><br></blockquote><blockquote type="cite"><span>(use-package :closer-mop)</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite">
<span>(defclass serializable-class (standard-class)</span><br></blockquote><blockquote type="cite"><span> ((database :initarg :database)))</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite">
<span>(defclass dummy-class (standard-class)</span><br></blockquote><blockquote type="cite"><span> ())</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>;; "layered serializable" metaclass</span><br>
</blockquote><blockquote type="cite"><span>(defclass combined-class1 (contextl:layered-class serializable-class)</span><br></blockquote><blockquote type="cite"><span> ())</span><br></blockquote><blockquote type="cite"><span></span><br>
</blockquote><blockquote type="cite"><span>;; another metaclass for comparison. Only difference is it inherits</span><br></blockquote><blockquote type="cite"><span>from dummy-class instead of layered-class.</span><br></blockquote>
<blockquote type="cite"><span>(defclass combined-class2 (dummy-class serializable-class)</span><br></blockquote><blockquote type="cite"><span> ())</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote>
<blockquote type="cite"><span>(defmethod validate-superclass ((class combined-class1) (superclass</span><br></blockquote><blockquote type="cite"><span>standard-class))</span><br></blockquote><blockquote type="cite"><span> t)</span><br>
</blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>(defmethod validate-superclass ((class combined-class2) (superclass</span><br></blockquote><blockquote type="cite"><span>standard-class))</span><br>
</blockquote><blockquote type="cite"><span> t)</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>;; Trying to create a class that uses serializable-class as its metaclass causes</span><br>
</blockquote><blockquote type="cite"><span>;; the error "invalid initialisation argument :DATABASE"</span><br></blockquote><blockquote type="cite"><span>(defclass try1 ()</span><br></blockquote><blockquote type="cite">
<span> ()</span><br></blockquote><blockquote type="cite"><span> (:metaclass combined-class1)</span><br></blockquote><blockquote type="cite"><span> (:database . "mydb"))</span><br></blockquote><blockquote type="cite">
<span></span><br></blockquote><blockquote type="cite"><span>;; So we define the following methods to disable checking of initargs...</span><br></blockquote><blockquote type="cite"><span>(defmethod initialize-instance :around ((c combined-class1) &rest args)</span><br>
</blockquote><blockquote type="cite"><span> (if (next-method-p)</span><br></blockquote><blockquote type="cite"><span>     (apply #'call-next-method c :allow-other-keys t args)))</span><br></blockquote><blockquote type="cite">
<span></span><br></blockquote><blockquote type="cite"><span>(defmethod reinitialize-instance :around ((c combined-class1) &rest args)</span><br></blockquote><blockquote type="cite"><span> (if (next-method-p)</span><br>
</blockquote><blockquote type="cite"><span>     (apply #'call-next-method c :allow-other-keys t args)))</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>;; Now (defclass try1) works ... but 'database' slot of the resulting</span><br>
</blockquote><blockquote type="cite"><span>class is unbound.</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>;; In contrast, if we define basically the same :around methods for</span><br>
</blockquote><blockquote type="cite"><span>;; combined-class2:</span><br></blockquote><blockquote type="cite"><span>(defmethod initialize-instance :around ((c combined-class2) &rest args)</span><br></blockquote><blockquote type="cite">
<span> (if (next-method-p)</span><br></blockquote><blockquote type="cite"><span>     (apply #'call-next-method c :allow-other-keys t args)))</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote>
<blockquote type="cite"><span>(defmethod reinitialize-instance :around ((c combined-class2) &rest args)</span><br></blockquote><blockquote type="cite"><span> (if (next-method-p)</span><br></blockquote><blockquote type="cite">
<span>     (apply #'call-next-method c :allow-other-keys t args)))</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>;; ...And create a class with class2 as its metaclass...</span><br>
</blockquote><blockquote type="cite"><span>(defclass try2 ()</span><br></blockquote><blockquote type="cite"><span> ()</span><br></blockquote><blockquote type="cite"><span> (:metaclass combined-class2)</span><br></blockquote>
<blockquote type="cite"><span> (:database . "mydb"))</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>;; Then this works. The resulting class has its :database slot correctly</span><br>
</blockquote><blockquote type="cite"><span>;; bound to the value "mydb"</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>The most obvious explanation is that contextl is somehow discarding</span><br>
</blockquote><blockquote type="cite"><span>keyword args that it does not recognise, preventing them from being</span><br></blockquote><blockquote type="cite"><span>seen by other initialisation methods. Is there an alternative</span><br>
</blockquote><blockquote type="cite"><span>explanation I am missing?</span><br></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite"><span>On 16 March 2012 07:59, Pascal Costanza <<a href="mailto:pc@p-cos.net">pc@p-cos.net</a>> wrote:</span><br>
</blockquote><blockquote type="cite"><blockquote type="cite"><span>Hi Paul,</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite">
<blockquote type="cite"><span>I'm hesitating to make such a change, because it would weaken checking initialization arguments for validity.</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">
<span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>Under normal circumstances, it is possible to make more initialization arguments valid for subclasses. See Section 7.1.2 of the HyperSpec. This also applies to metaobject classes. If for some reason this doesn't work for you, I would like to know about it and see whether something needs to be fixed. Please send some example, and some information which CL implementation you are using to test this.</span><br>
</blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>Pascal</span><br></blockquote></blockquote><blockquote type="cite">
<blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>P.S.: I'm curious to hear about what you use ContextL for, and what you are adding in your subclasses. If you prefer, please feel free to contact me by private email on this. Thanks.</span><br>
</blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>On 14 Mar 2012, at 21:56, Paul Sexton wrote:</span><br>
</blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>Hi</span><br></blockquote>
</blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite">
<span>At present the metaclasses in contextl choke during initialisation if</span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>they are passed keys that they do not recognise. This makes it very</span><br>
</blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>difficult to create metaclasses derived from those classes, if the</span><br></blockquote></blockquote></blockquote>
<blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>derived metaclasses need to be passed their own arguments a la</span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">
<blockquote type="cite"><span>':in-layer'.</span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote></blockquote>
<blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>Including &allow-other-keys in the argument lists for</span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">
<blockquote type="cite"><span>(re)initialize-instance in cx-classes-in-layer.lisp and</span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have</span><br>
</blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>any downsides. Would you consider making this change?</span><br></blockquote></blockquote></blockquote><blockquote type="cite">
<blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>Thanks</span><br></blockquote></blockquote>
</blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>Paul</span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span></span><br>
</blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span>_______________________________________________</span><br></blockquote></blockquote></blockquote><blockquote type="cite">
<blockquote type="cite"><blockquote type="cite"><span>closer-devel mailing list</span><br></blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span><a href="mailto:closer-devel@common-lisp.net">closer-devel@common-lisp.net</a></span><br>
</blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><blockquote type="cite"><span><a href="http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel">http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel</a></span><br>
</blockquote></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span>--</span><br></blockquote></blockquote>
<blockquote type="cite"><blockquote type="cite"><span>Pascal Costanza</span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite">
<blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><span></span><br></blockquote></blockquote><blockquote type="cite"><span></span><br></blockquote><blockquote type="cite">
<span>_______________________________________________</span><br></blockquote><blockquote type="cite"><span>closer-devel mailing list</span><br></blockquote><blockquote type="cite"><span><a href="mailto:closer-devel@common-lisp.net">closer-devel@common-lisp.net</a></span><br>
</blockquote><blockquote type="cite"><span><a href="http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel">http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel</a></span><br></blockquote><span></span><br>
<span>--</span><br><span>Pascal Costanza</span><br><span></span><br><span></span><br><span></span><br><span></span><br><span></span><br><span></span><br><span>------------------------------</span><br><span></span><br><span>_______________________________________________</span><br>
<span>closer-devel mailing list</span><br><span><a href="mailto:closer-devel@common-lisp.net">closer-devel@common-lisp.net</a></span><br><span><a href="http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel">http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel</a></span><br>
<span></span><br><span></span><br><span>End of closer-devel Digest, Vol 56, Issue 3</span><br><span>*******************************************</span><br></div></blockquote></body></html>