Hi,
What the subject line says. Here is a test case:
CL-USER(1): (use-package :mop) T CL-USER(2): (defclass my-method (standard-method) ()) #<STANDARD-CLASS MY-METHOD {1EE9DE5F}> CL-USER(3): (defclass my-generic-function (standard-generic-function) () (:metaclass funcallable-standard-class) (:default-initargs :method-class (find-class 'my-method))) #<FUNCALLABLE-STANDARD-CLASS MY-GENERIC-FUNCTION {6E06D676}> CL-USER(4): (defgeneric my-function () (:generic-function-class my-generic-function)) #<MY-GENERIC-FUNCTION MY-FUNCTION {2EA1569}> CL-USER(5): (generic-function-method-class #'my-function) #<STANDARD-CLASS STANDARD-METHOD {4E513D61}>
The reason is that the defaulting happens in the keyword arguments for ensure-generic-function (in clos.lisp), which thus overrides any default initargs. However, the defaulting should be left to the class.
Pascal
-- Pascal Costanza
On Dec 9, 2012, at 17:07, Pascal Costanza pc@p-cos.net wrote:
Hi,
What the subject line says. Here is a test case:
CL-USER(1): (use-package :mop) T CL-USER(2): (defclass my-method (standard-method) ()) #<STANDARD-CLASS MY-METHOD {1EE9DE5F}> CL-USER(3): (defclass my-generic-function (standard-generic-function) () (:metaclass funcallable-standard-class) (:default-initargs :method-class (find-class 'my-method))) #<FUNCALLABLE-STANDARD-CLASS MY-GENERIC-FUNCTION {6E06D676}> CL-USER(4): (defgeneric my-function () (:generic-function-class my-generic-function)) #<MY-GENERIC-FUNCTION MY-FUNCTION {2EA1569}> CL-USER(5): (generic-function-method-class #'my-function) #<STANDARD-CLASS STANDARD-METHOD {4E513D61}>
The reason is that the defaulting happens in the keyword arguments for ensure-generic-function (in clos.lisp), which thus overrides any default initargs. However, the defaulting should be left to the class.
Thanks, logged at http://trac.common-lisp.net/armedbear/ticket/279
Rudi
On Dec 9, 2012, at 17:07, Pascal Costanza pc@p-cos.net wrote:
Hi,
What the subject line says. Here is a test case:
[...]
Thanks, this should be fixed in r14344.
Rudi
On 30 Dec 2012, at 18:11, Rudolf Schlatte rudi@constantly.at wrote:
On Dec 9, 2012, at 17:07, Pascal Costanza pc@p-cos.net wrote:
Hi,
What the subject line says. Here is a test case:
[...]
Thanks, this should be fixed in r14344.
OK, this looks pretty good. More and more of my tests succeed.
I am now running into an issue which is admittedly not a bug in the strict sense, but I would encourage you to consider changing the existing behavior anyway: In ensure-generic-function-using-class, abcl is making a few sanity checks and issuing errors, and it is correct to do so according to the HyperSpec. However, since they are done already at such an early stage, some useful MOP idioms are not easily expressible, or at least need to be expressed differently, and I think it would be better to perform the checks at a later stage, for example inside shared-initialize.
The concrete case that I encounter is the :lambda-list initialization parameter. In AspectL and filtered-functions, I need to be able to modify the lambda list internally, by adding one or two extra required parameters. I do this, extremely roughly, as follows:
(defmethod initialize-instance :around ((gf my-generic-function) &rest initargs &key lambda-list) (apply #'call-next-method gf :lambda-list (list* extra-parameters… lambda-list) initargs))
All methods that are added to such generic functions also get the extra parameters padded in during method metaobject initialization. However, due to this, the lambda list that ensure-generic-function-using-class sees is, by definition, not congruent with potentially existing methods, and thus complains about this fact with an error. If the check would only occur later (for example in shared-initialize on standard-generic-function), then the modifications would correctly pass through. At least, that is the case in all the other MOP implementations in which AspectL and filtered-functions work.
Again, nothing in the HyperSpec and the CLOS MOP specifications specify where the checks must take place, so you can rightfully choose to keep things as they are. I would then have to change AspectL and filtered-functions to modify the lambda list in an around method on ensure-generic-function-using-class (which would not be 100% portable, though).
What are your thoughts on this?
Best, Pascal
P.S.: All the best for 2013!!!
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On Jan 1, 2013, at 21:36, Pascal Costanza pc@p-cos.net wrote:
OK, this looks pretty good. More and more of my tests succeed.
I am now running into an issue which is admittedly not a bug in the strict sense, but I would encourage you to consider changing the existing behavior anyway: In ensure-generic-function-using-class, abcl is making a few sanity checks and issuing errors, and it is correct to do so according to the HyperSpec. However, since they are done already at such an early stage, some useful MOP idioms are not easily expressible, or at least need to be expressed differently, and I think it would be better to perform the checks at a later stage, for example inside shared-initialize.
[...]
That sounds quite reasonable. Logged at http://trac.common-lisp.net/armedbear/ticket/284.
P.S.: All the best for 2013!!!
Thanks, same to you!
Rudi
On Jan 1, 2013, at 21:36, Pascal Costanza pc@p-cos.net wrote:
OK, this looks pretty good. More and more of my tests succeed.
I am now running into an issue which is admittedly not a bug in the strict sense, but I would encourage you to consider changing the existing behavior anyway: In ensure-generic-function-using-class, abcl is making a few sanity checks and issuing errors, and it is correct to do so according to the HyperSpec. However, since they are done already at such an early stage, some useful MOP idioms are not easily expressible, or at least need to be expressed differently, and I think it would be better to perform the checks at a later stage, for example inside shared-initialize.
Hi Pascal, r14347 moves the check for lambda list congruence to reinitialize-instance :before. I chose this location instead of shared-initialize since only in this case can we have existing methods. Changing method-class is actually allowed according to the hyperspec so that test is gone. I only did light testing (basically, building abcl and running ansi-tests) but I trust you'll let me know when something's broken. :)
Rudi
Hi Rudi,
Unfortunately, this is still not enough. (Although AspectL now seems to work, but filtered-functions don't work yet.)
In ensure-generic-function, there are still a number of computations going on that are based on information that may still be modified later on in user-defined :around methods on initialize-instance or reinitialize-instance. My concrete stumbling block is currently the information about required arguments that is returned by gf-required-args, which does not reflect any changes made to a lambda list in such :around methods. I immediately see similar potential problems with optional arguments, argument precedence order, and documentation (not sure if that is all).
You may want to look into this.
However, filtered-functions is a library that does not work well in a number of other CL implementations either. Everything else seems to work with ABCL, so I would already consider ABCL very mature with regard to CLOS MOP support, and wouldn't hesitate releasing official Closer to MOP support with the next official version of ABCL, even if this problem is not fixed beforehand…
Pascal
On 5 Jan 2013, at 19:46, Rudolf Schlatte rudi@constantly.at wrote:
On Jan 1, 2013, at 21:36, Pascal Costanza pc@p-cos.net wrote:
OK, this looks pretty good. More and more of my tests succeed.
I am now running into an issue which is admittedly not a bug in the strict sense, but I would encourage you to consider changing the existing behavior anyway: In ensure-generic-function-using-class, abcl is making a few sanity checks and issuing errors, and it is correct to do so according to the HyperSpec. However, since they are done already at such an early stage, some useful MOP idioms are not easily expressible, or at least need to be expressed differently, and I think it would be better to perform the checks at a later stage, for example inside shared-initialize.
Hi Pascal, r14347 moves the check for lambda list congruence to reinitialize-instance :before. I chose this location instead of shared-initialize since only in this case can we have existing methods. Changing method-class is actually allowed according to the hyperspec so that test is gone. I only did light testing (basically, building abcl and running ansi-tests) but I trust you'll let me know when something's broken. :)
Rudi
-- Pascal Costanza
armedbear-devel@common-lisp.net