From psexton.2a at gmail.com Wed Mar 14 20:56:43 2012 From: psexton.2a at gmail.com (Paul Sexton) Date: Thu, 15 Mar 2012 09:56:43 +1300 Subject: [closer-devel] ContextL: allow other keys in (re)initialize-instance methods for metaclasses Message-ID: Hi At present the metaclasses in contextl choke during initialisation if they are passed keys that they do not recognise. This makes it very difficult to create metaclasses derived from those classes, if the derived metaclasses need to be passed their own arguments a la ':in-layer'. Including &allow-other-keys in the argument lists for (re)initialize-instance in cx-classes-in-layer.lisp and cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have any downsides. Would you consider making this change? Thanks Paul From pc at p-cos.net Thu Mar 15 18:59:06 2012 From: pc at p-cos.net (Pascal Costanza) Date: Thu, 15 Mar 2012 19:59:06 +0100 Subject: [closer-devel] ContextL: allow other keys in (re)initialize-instance methods for metaclasses In-Reply-To: References: Message-ID: Hi Paul, I'm hesitating to make such a change, because it would weaken checking initialization arguments for validity. 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. Pascal 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. On 14 Mar 2012, at 21:56, Paul Sexton wrote: > Hi > > At present the metaclasses in contextl choke during initialisation if > they are passed keys that they do not recognise. This makes it very > difficult to create metaclasses derived from those classes, if the > derived metaclasses need to be passed their own arguments a la > ':in-layer'. > > Including &allow-other-keys in the argument lists for > (re)initialize-instance in cx-classes-in-layer.lisp and > cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have > any downsides. Would you consider making this change? > > Thanks > Paul > > _______________________________________________ > closer-devel mailing list > closer-devel at common-lisp.net > http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel -- Pascal Costanza From psexton.2a at gmail.com Fri Mar 16 00:32:29 2012 From: psexton.2a at gmail.com (Paul Sexton) Date: Fri, 16 Mar 2012 13:32:29 +1300 Subject: [closer-devel] ContextL: allow other keys in (re)initialize-instance methods for metaclasses In-Reply-To: References: Message-ID: Thanks -- I have figured out how to stop the error from occurring, but I now have a different problem: the initargs for classes other than layered-class seem to get ignored and do not result in values being stored in the class' slots. Here is a simple example. --------------------- (use-package :closer-mop) (defclass serializable-class (standard-class) ((database :initarg :database))) (defclass dummy-class (standard-class) ()) ;; "layered serializable" metaclass (defclass combined-class1 (contextl:layered-class serializable-class) ()) ;; another metaclass for comparison. Only difference is it inherits from dummy-class instead of layered-class. (defclass combined-class2 (dummy-class serializable-class) ()) (defmethod validate-superclass ((class combined-class1) (superclass standard-class)) t) (defmethod validate-superclass ((class combined-class2) (superclass standard-class)) t) ;; Trying to create a class that uses serializable-class as its metaclass causes ;; the error "invalid initialisation argument :DATABASE" (defclass try1 () () (:metaclass combined-class1) (:database . "mydb")) ;; So we define the following methods to disable checking of initargs... (defmethod initialize-instance :around ((c combined-class1) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) (defmethod reinitialize-instance :around ((c combined-class1) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) ;; Now (defclass try1) works ... but 'database' slot of the resulting class is unbound. ;; In contrast, if we define basically the same :around methods for ;; combined-class2: (defmethod initialize-instance :around ((c combined-class2) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) (defmethod reinitialize-instance :around ((c combined-class2) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) ;; ...And create a class with class2 as its metaclass... (defclass try2 () () (:metaclass combined-class2) (:database . "mydb")) ;; Then this works. The resulting class has its :database slot correctly ;; bound to the value "mydb" The most obvious explanation is that contextl is somehow discarding keyword args that it does not recognise, preventing them from being seen by other initialisation methods. Is there an alternative explanation I am missing? On 16 March 2012 07:59, Pascal Costanza wrote: > Hi Paul, > > I'm hesitating to make such a change, because it would weaken checking initialization arguments for validity. > > 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. > > Pascal > > 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. > > On 14 Mar 2012, at 21:56, Paul Sexton wrote: > >> Hi >> >> At present the metaclasses in contextl choke during initialisation if >> they are passed keys that they do not recognise. This makes it very >> difficult to create metaclasses derived from those classes, if the >> derived metaclasses need to be passed their own arguments a la >> ':in-layer'. >> >> Including &allow-other-keys in the argument lists for >> (re)initialize-instance in cx-classes-in-layer.lisp and >> cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have >> any downsides. Would you consider making this change? >> >> Thanks >> Paul >> >> _______________________________________________ >> closer-devel mailing list >> closer-devel at common-lisp.net >> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel > > -- > Pascal Costanza > > > From pc at p-cos.net Sun Mar 18 16:10:11 2012 From: pc at p-cos.net (Pascal Costanza) Date: Sun, 18 Mar 2012 17:10:11 +0100 Subject: [closer-devel] ContextL: allow other keys in (re)initialize-instance methods for metaclasses In-Reply-To: References: Message-ID: <4B1FC6C3-FAD1-4DAF-BA50-8AB687EE6259@p-cos.net> Hi Paul, 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. 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). 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. 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: (in-package :contextl-user) (defclass serializable-class (standard-class) ((database :initarg :database))) (defclass combined-class (layered-class serializable-class) ()) (defmethod validate-superclass ((class combined-class) (superclass standard-class)) t) (defmethod partial-class-base-initargs append ((class combined-class)) '(:database)) (defclass try () () (:metaclass combined-class) (:database . "mydb")) (finalize-inheritance (find-class 'try)) (assert (string= (slot-value (find-class 'try) 'database) "mydb")) (assert (loop for class in (rest (class-precedence-list (find-class 'try))) never (slot-exists-p class 'database))) This is now also part of the test suite for ContextL. 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. Best, Pascal On 16 Mar 2012, at 01:32, Paul Sexton wrote: > Thanks -- I have figured out how to stop the error from occurring, but > I now have a different problem: the initargs for classes other than > layered-class seem to get ignored and do not result in values being > stored in the class' slots. > > Here is a simple example. > --------------------- > (use-package :closer-mop) > > (defclass serializable-class (standard-class) > ((database :initarg :database))) > > (defclass dummy-class (standard-class) > ()) > > ;; "layered serializable" metaclass > (defclass combined-class1 (contextl:layered-class serializable-class) > ()) > > ;; another metaclass for comparison. Only difference is it inherits > from dummy-class instead of layered-class. > (defclass combined-class2 (dummy-class serializable-class) > ()) > > (defmethod validate-superclass ((class combined-class1) (superclass > standard-class)) > t) > > (defmethod validate-superclass ((class combined-class2) (superclass > standard-class)) > t) > > ;; Trying to create a class that uses serializable-class as its metaclass causes > ;; the error "invalid initialisation argument :DATABASE" > (defclass try1 () > () > (:metaclass combined-class1) > (:database . "mydb")) > > ;; So we define the following methods to disable checking of initargs... > (defmethod initialize-instance :around ((c combined-class1) &rest args) > (if (next-method-p) > (apply #'call-next-method c :allow-other-keys t args))) > > (defmethod reinitialize-instance :around ((c combined-class1) &rest args) > (if (next-method-p) > (apply #'call-next-method c :allow-other-keys t args))) > > ;; Now (defclass try1) works ... but 'database' slot of the resulting > class is unbound. > > ;; In contrast, if we define basically the same :around methods for > ;; combined-class2: > (defmethod initialize-instance :around ((c combined-class2) &rest args) > (if (next-method-p) > (apply #'call-next-method c :allow-other-keys t args))) > > (defmethod reinitialize-instance :around ((c combined-class2) &rest args) > (if (next-method-p) > (apply #'call-next-method c :allow-other-keys t args))) > > ;; ...And create a class with class2 as its metaclass... > (defclass try2 () > () > (:metaclass combined-class2) > (:database . "mydb")) > > ;; Then this works. The resulting class has its :database slot correctly > ;; bound to the value "mydb" > > The most obvious explanation is that contextl is somehow discarding > keyword args that it does not recognise, preventing them from being > seen by other initialisation methods. Is there an alternative > explanation I am missing? > > On 16 March 2012 07:59, Pascal Costanza wrote: >> Hi Paul, >> >> I'm hesitating to make such a change, because it would weaken checking initialization arguments for validity. >> >> 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. >> >> Pascal >> >> 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. >> >> On 14 Mar 2012, at 21:56, Paul Sexton wrote: >> >>> Hi >>> >>> At present the metaclasses in contextl choke during initialisation if >>> they are passed keys that they do not recognise. This makes it very >>> difficult to create metaclasses derived from those classes, if the >>> derived metaclasses need to be passed their own arguments a la >>> ':in-layer'. >>> >>> Including &allow-other-keys in the argument lists for >>> (re)initialize-instance in cx-classes-in-layer.lisp and >>> cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have >>> any downsides. Would you consider making this change? >>> >>> Thanks >>> Paul >>> >>> _______________________________________________ >>> closer-devel mailing list >>> closer-devel at common-lisp.net >>> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel >> >> -- >> Pascal Costanza >> >> >> > > _______________________________________________ > closer-devel mailing list > closer-devel at common-lisp.net > http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel -- Pascal Costanza From danlentz at gmail.com Sun Mar 18 19:23:40 2012 From: danlentz at gmail.com (Dan Lentz) Date: Sun, 18 Mar 2012 15:23:40 -0400 Subject: [closer-devel] closer-devel Digest, Vol 56, Issue 3 In-Reply-To: References: Message-ID: <-5440386027639134106@unknownmsgid> 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? 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? Message: 1 Date: Sun, 18 Mar 2012 17:10:11 +0100 From: Pascal Costanza To: Paul Sexton Cc: closer-devel at common-lisp.net Subject: Re: [closer-devel] ContextL: allow other keys in (re)initialize-instance methods for metaclasses Message-ID: <4B1FC6C3-FAD1-4DAF-BA50-8AB687EE6259 at p-cos.net> Content-Type: text/plain; charset=us-ascii Hi Paul, 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. 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). 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. 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: (in-package :contextl-user) (defclass serializable-class (standard-class) ((database :initarg :database))) (defclass combined-class (layered-class serializable-class) ()) (defmethod validate-superclass ((class combined-class) (superclass standard-class)) t) (defmethod partial-class-base-initargs append ((class combined-class)) '(:database)) (defclass try () () (:metaclass combined-class) (:database . "mydb")) (finalize-inheritance (find-class 'try)) (assert (string= (slot-value (find-class 'try) 'database) "mydb")) (assert (loop for class in (rest (class-precedence-list (find-class 'try))) never (slot-exists-p class 'database))) This is now also part of the test suite for ContextL. 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. Best, Pascal On 16 Mar 2012, at 01:32, Paul Sexton wrote: Thanks -- I have figured out how to stop the error from occurring, but I now have a different problem: the initargs for classes other than layered-class seem to get ignored and do not result in values being stored in the class' slots. Here is a simple example. --------------------- (use-package :closer-mop) (defclass serializable-class (standard-class) ((database :initarg :database))) (defclass dummy-class (standard-class) ()) ;; "layered serializable" metaclass (defclass combined-class1 (contextl:layered-class serializable-class) ()) ;; another metaclass for comparison. Only difference is it inherits from dummy-class instead of layered-class. (defclass combined-class2 (dummy-class serializable-class) ()) (defmethod validate-superclass ((class combined-class1) (superclass standard-class)) t) (defmethod validate-superclass ((class combined-class2) (superclass standard-class)) t) ;; Trying to create a class that uses serializable-class as its metaclass causes ;; the error "invalid initialisation argument :DATABASE" (defclass try1 () () (:metaclass combined-class1) (:database . "mydb")) ;; So we define the following methods to disable checking of initargs... (defmethod initialize-instance :around ((c combined-class1) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) (defmethod reinitialize-instance :around ((c combined-class1) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) ;; Now (defclass try1) works ... but 'database' slot of the resulting class is unbound. ;; In contrast, if we define basically the same :around methods for ;; combined-class2: (defmethod initialize-instance :around ((c combined-class2) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) (defmethod reinitialize-instance :around ((c combined-class2) &rest args) (if (next-method-p) (apply #'call-next-method c :allow-other-keys t args))) ;; ...And create a class with class2 as its metaclass... (defclass try2 () () (:metaclass combined-class2) (:database . "mydb")) ;; Then this works. The resulting class has its :database slot correctly ;; bound to the value "mydb" The most obvious explanation is that contextl is somehow discarding keyword args that it does not recognise, preventing them from being seen by other initialisation methods. Is there an alternative explanation I am missing? On 16 March 2012 07:59, Pascal Costanza wrote: Hi Paul, I'm hesitating to make such a change, because it would weaken checking initialization arguments for validity. 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. Pascal 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. On 14 Mar 2012, at 21:56, Paul Sexton wrote: Hi At present the metaclasses in contextl choke during initialisation if they are passed keys that they do not recognise. This makes it very difficult to create metaclasses derived from those classes, if the derived metaclasses need to be passed their own arguments a la ':in-layer'. Including &allow-other-keys in the argument lists for (re)initialize-instance in cx-classes-in-layer.lisp and cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have any downsides. Would you consider making this change? Thanks Paul _______________________________________________ closer-devel mailing list closer-devel at common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel -- Pascal Costanza _______________________________________________ closer-devel mailing list closer-devel at common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel -- Pascal Costanza ------------------------------ _______________________________________________ closer-devel mailing list closer-devel at common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel End of closer-devel Digest, Vol 56, Issue 3 ******************************************* -------------- next part -------------- An HTML attachment was scrubbed... URL: From psexton.2a at gmail.com Sun Mar 18 20:20:24 2012 From: psexton.2a at gmail.com (Paul Sexton) Date: Mon, 19 Mar 2012 09:20:24 +1300 Subject: [closer-devel] ContextL: allow other keys in (re)initialize-instance methods for metaclasses In-Reply-To: <4B1FC6C3-FAD1-4DAF-BA50-8AB687EE6259@p-cos.net> References: <4B1FC6C3-FAD1-4DAF-BA50-8AB687EE6259@p-cos.net> Message-ID: <-8168371131945964316@unknownmsgid> It seems to work. Thanks a lot for the quick fix! I'm glad my report was helpful. Paul On 19 Mar 2012, at 05:10, Pascal Costanza wrote: > Hi Paul, > > 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. > > 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). > > 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. > > 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: > > (in-package :contextl-user) > > (defclass serializable-class (standard-class) > ((database :initarg :database))) > > (defclass combined-class (layered-class serializable-class) > ()) > > (defmethod validate-superclass ((class combined-class) (superclass standard-class)) > t) > > (defmethod partial-class-base-initargs append ((class combined-class)) > '(:database)) > > (defclass try () > () > (:metaclass combined-class) > (:database . "mydb")) > > (finalize-inheritance (find-class 'try)) > > (assert (string= (slot-value (find-class 'try) 'database) "mydb")) > > (assert (loop for class in (rest (class-precedence-list (find-class 'try))) > never (slot-exists-p class 'database))) > > This is now also part of the test suite for ContextL. > > 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. > > > Best, > Pascal > > On 16 Mar 2012, at 01:32, Paul Sexton wrote: > >> Thanks -- I have figured out how to stop the error from occurring, but >> I now have a different problem: the initargs for classes other than >> layered-class seem to get ignored and do not result in values being >> stored in the class' slots. >> >> Here is a simple example. >> --------------------- >> (use-package :closer-mop) >> >> (defclass serializable-class (standard-class) >> ((database :initarg :database))) >> >> (defclass dummy-class (standard-class) >> ()) >> >> ;; "layered serializable" metaclass >> (defclass combined-class1 (contextl:layered-class serializable-class) >> ()) >> >> ;; another metaclass for comparison. Only difference is it inherits >> from dummy-class instead of layered-class. >> (defclass combined-class2 (dummy-class serializable-class) >> ()) >> >> (defmethod validate-superclass ((class combined-class1) (superclass >> standard-class)) >> t) >> >> (defmethod validate-superclass ((class combined-class2) (superclass >> standard-class)) >> t) >> >> ;; Trying to create a class that uses serializable-class as its metaclass causes >> ;; the error "invalid initialisation argument :DATABASE" >> (defclass try1 () >> () >> (:metaclass combined-class1) >> (:database . "mydb")) >> >> ;; So we define the following methods to disable checking of initargs... >> (defmethod initialize-instance :around ((c combined-class1) &rest args) >> (if (next-method-p) >> (apply #'call-next-method c :allow-other-keys t args))) >> >> (defmethod reinitialize-instance :around ((c combined-class1) &rest args) >> (if (next-method-p) >> (apply #'call-next-method c :allow-other-keys t args))) >> >> ;; Now (defclass try1) works ... but 'database' slot of the resulting >> class is unbound. >> >> ;; In contrast, if we define basically the same :around methods for >> ;; combined-class2: >> (defmethod initialize-instance :around ((c combined-class2) &rest args) >> (if (next-method-p) >> (apply #'call-next-method c :allow-other-keys t args))) >> >> (defmethod reinitialize-instance :around ((c combined-class2) &rest args) >> (if (next-method-p) >> (apply #'call-next-method c :allow-other-keys t args))) >> >> ;; ...And create a class with class2 as its metaclass... >> (defclass try2 () >> () >> (:metaclass combined-class2) >> (:database . "mydb")) >> >> ;; Then this works. The resulting class has its :database slot correctly >> ;; bound to the value "mydb" >> >> The most obvious explanation is that contextl is somehow discarding >> keyword args that it does not recognise, preventing them from being >> seen by other initialisation methods. Is there an alternative >> explanation I am missing? >> >> On 16 March 2012 07:59, Pascal Costanza wrote: >>> Hi Paul, >>> >>> I'm hesitating to make such a change, because it would weaken checking initialization arguments for validity. >>> >>> 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. >>> >>> Pascal >>> >>> 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. >>> >>> On 14 Mar 2012, at 21:56, Paul Sexton wrote: >>> >>>> Hi >>>> >>>> At present the metaclasses in contextl choke during initialisation if >>>> they are passed keys that they do not recognise. This makes it very >>>> difficult to create metaclasses derived from those classes, if the >>>> derived metaclasses need to be passed their own arguments a la >>>> ':in-layer'. >>>> >>>> Including &allow-other-keys in the argument lists for >>>> (re)initialize-instance in cx-classes-in-layer.lisp and >>>> cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have >>>> any downsides. Would you consider making this change? >>>> >>>> Thanks >>>> Paul >>>> >>>> _______________________________________________ >>>> closer-devel mailing list >>>> closer-devel at common-lisp.net >>>> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel >>> >>> -- >>> Pascal Costanza >>> >>> >>> >> >> _______________________________________________ >> closer-devel mailing list >> closer-devel at common-lisp.net >> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel > > -- > Pascal Costanza > > > From pc at p-cos.net Sun Mar 18 21:57:54 2012 From: pc at p-cos.net (Pascal Costanza) Date: Sun, 18 Mar 2012 22:57:54 +0100 Subject: [closer-devel] closer-devel Digest, Vol 56, Issue 3 In-Reply-To: <-5440386027639134106@unknownmsgid> References: <-5440386027639134106@unknownmsgid> Message-ID: Hi, Unfortunately, there is only so much time I can afford to invest in this. Although I agree more documentation would be definitely very useful, I can only do very little in that direction right now. Please feel free to ask questions, though, I can easily be lured into thinking about interesting ones. ;) Closer-devel is a good mailing list for such questions, as is the pro mailing list at http://lists.common-lisp.net/cgi-bin/mailman/listinfo/pro - which may be more appropriate, depending on use case. (I follow both lists.) Best, Pascal On 18 Mar 2012, at 20:23, Dan Lentz wrote: > 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? > > 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? > >> >> >> Message: 1 >> Date: Sun, 18 Mar 2012 17:10:11 +0100 >> From: Pascal Costanza >> To: Paul Sexton >> Cc: closer-devel at common-lisp.net >> Subject: Re: [closer-devel] ContextL: allow other keys in >> (re)initialize-instance methods for metaclasses >> Message-ID: <4B1FC6C3-FAD1-4DAF-BA50-8AB687EE6259 at p-cos.net> >> Content-Type: text/plain; charset=us-ascii >> >> Hi Paul, >> >> 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. >> >> 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). >> >> 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. >> >> 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: >> >> (in-package :contextl-user) >> >> (defclass serializable-class (standard-class) >> ((database :initarg :database))) >> >> (defclass combined-class (layered-class serializable-class) >> ()) >> >> (defmethod validate-superclass ((class combined-class) (superclass standard-class)) >> t) >> >> (defmethod partial-class-base-initargs append ((class combined-class)) >> '(:database)) >> >> (defclass try () >> () >> (:metaclass combined-class) >> (:database . "mydb")) >> >> (finalize-inheritance (find-class 'try)) >> >> (assert (string= (slot-value (find-class 'try) 'database) "mydb")) >> >> (assert (loop for class in (rest (class-precedence-list (find-class 'try))) >> never (slot-exists-p class 'database))) >> >> This is now also part of the test suite for ContextL. >> >> 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. >> >> >> Best, >> Pascal >> >> On 16 Mar 2012, at 01:32, Paul Sexton wrote: >> >>> Thanks -- I have figured out how to stop the error from occurring, but >>> I now have a different problem: the initargs for classes other than >>> layered-class seem to get ignored and do not result in values being >>> stored in the class' slots. >>> >>> Here is a simple example. >>> --------------------- >>> (use-package :closer-mop) >>> >>> (defclass serializable-class (standard-class) >>> ((database :initarg :database))) >>> >>> (defclass dummy-class (standard-class) >>> ()) >>> >>> ;; "layered serializable" metaclass >>> (defclass combined-class1 (contextl:layered-class serializable-class) >>> ()) >>> >>> ;; another metaclass for comparison. Only difference is it inherits >>> from dummy-class instead of layered-class. >>> (defclass combined-class2 (dummy-class serializable-class) >>> ()) >>> >>> (defmethod validate-superclass ((class combined-class1) (superclass >>> standard-class)) >>> t) >>> >>> (defmethod validate-superclass ((class combined-class2) (superclass >>> standard-class)) >>> t) >>> >>> ;; Trying to create a class that uses serializable-class as its metaclass causes >>> ;; the error "invalid initialisation argument :DATABASE" >>> (defclass try1 () >>> () >>> (:metaclass combined-class1) >>> (:database . "mydb")) >>> >>> ;; So we define the following methods to disable checking of initargs... >>> (defmethod initialize-instance :around ((c combined-class1) &rest args) >>> (if (next-method-p) >>> (apply #'call-next-method c :allow-other-keys t args))) >>> >>> (defmethod reinitialize-instance :around ((c combined-class1) &rest args) >>> (if (next-method-p) >>> (apply #'call-next-method c :allow-other-keys t args))) >>> >>> ;; Now (defclass try1) works ... but 'database' slot of the resulting >>> class is unbound. >>> >>> ;; In contrast, if we define basically the same :around methods for >>> ;; combined-class2: >>> (defmethod initialize-instance :around ((c combined-class2) &rest args) >>> (if (next-method-p) >>> (apply #'call-next-method c :allow-other-keys t args))) >>> >>> (defmethod reinitialize-instance :around ((c combined-class2) &rest args) >>> (if (next-method-p) >>> (apply #'call-next-method c :allow-other-keys t args))) >>> >>> ;; ...And create a class with class2 as its metaclass... >>> (defclass try2 () >>> () >>> (:metaclass combined-class2) >>> (:database . "mydb")) >>> >>> ;; Then this works. The resulting class has its :database slot correctly >>> ;; bound to the value "mydb" >>> >>> The most obvious explanation is that contextl is somehow discarding >>> keyword args that it does not recognise, preventing them from being >>> seen by other initialisation methods. Is there an alternative >>> explanation I am missing? >>> >>> On 16 March 2012 07:59, Pascal Costanza wrote: >>>> Hi Paul, >>>> >>>> I'm hesitating to make such a change, because it would weaken checking initialization arguments for validity. >>>> >>>> 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. >>>> >>>> Pascal >>>> >>>> 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. >>>> >>>> On 14 Mar 2012, at 21:56, Paul Sexton wrote: >>>> >>>>> Hi >>>>> >>>>> At present the metaclasses in contextl choke during initialisation if >>>>> they are passed keys that they do not recognise. This makes it very >>>>> difficult to create metaclasses derived from those classes, if the >>>>> derived metaclasses need to be passed their own arguments a la >>>>> ':in-layer'. >>>>> >>>>> Including &allow-other-keys in the argument lists for >>>>> (re)initialize-instance in cx-classes-in-layer.lisp and >>>>> cx-layer-metaclasses.lisp seems to fix this, and doesn't seem to have >>>>> any downsides. Would you consider making this change? >>>>> >>>>> Thanks >>>>> Paul >>>>> >>>>> _______________________________________________ >>>>> closer-devel mailing list >>>>> closer-devel at common-lisp.net >>>>> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel >>>> >>>> -- >>>> Pascal Costanza >>>> >>>> >>>> >>> >>> _______________________________________________ >>> closer-devel mailing list >>> closer-devel at common-lisp.net >>> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel >> >> -- >> Pascal Costanza >> >> >> >> >> >> >> ------------------------------ >> >> _______________________________________________ >> closer-devel mailing list >> closer-devel at common-lisp.net >> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel >> >> >> End of closer-devel Digest, Vol 56, Issue 3 >> ******************************************* > _______________________________________________ > closer-devel mailing list > closer-devel at common-lisp.net > http://lists.common-lisp.net/cgi-bin/mailman/listinfo/closer-devel -- Pascal Costanza -------------- next part -------------- An HTML attachment was scrubbed... URL: