On 2 Jul 2004, at 11:52, Christophe Rhodes wrote:
> In general, sadly, questions that are formulated like this about the
> MOP will tend to be answered by "I don't know". The MOP specification
> is, well, not terribly tight; furthermore, the specification and the
> implementation written by the same people diverge in behaviour... and
> (with one possible exception, but I don't think he reads this list,
> and in any case he's been inactive for quite a while) the cmucl/sbcl
> community contains no MOP experts. (For more evidence of this, see my
> replies to Edwin M Westbrook of yesterday on sbcl-devel).
OK, sorry about that.
> So, that said, what would greatly assist in this kind of discussion is
> a slightly more precise problem description.
OK, I have hacked around a bit, and I think I can provide a better
question. In fact, I think I have detected a bug. Here is the code:
(defmethod compute-discriminating-function
((gf special-generic-function))
(let ((dfun (call-next-method))
(dynamic-scope-prototype (class-prototype (dynamic-scope gf))))
(lambda (&rest args)
(declare (dynamic-extent args))
(apply dfun dynamic-scope-prototype args))))
I have checked the MOP specs, and this should work. (The MOP explicitly
states that one can override compute-discriminating-function, which
includes modifying the return value of call-next-method.)
However, when I call an example function, I get the following condition:
The value
#<SB-PCL::WRAPPER #<FUNCALLABLE-STANDARD-CLASS
SPECIAL-GENERIC-FUNCTION>
{4000BB71}>
is not of type
(OR FUNCTION SYMBOL).
[Condition of type TYPE-ERROR]
Restarts:
0: [ABORT] Abort handling SLIME request.
1: [ABORT] Reduce debugger level (leaving debugger, returning to
toplevel).
2: [TOPLEVEL] Restart at toplevel READ/EVAL/PRINT loop.
Backtrace:
0: (SB-KERNEL:%COERCE-CALLABLE-TO-FUN 1 #<SB-PCL::WRAPPER
#<FUNCALLABLE-STANDARD-CLASS SPECIAL-GENERIC-FUNCTION>
{4000BB71}>)[:EXTERNAL]
1: ("varargs entry for #'(LAMBDA (&REST ASPECTL.DYNACLOS::ARGS)
(DECLARE #) ...)" 5)
2: (SB-INT:EVAL-IN-LEXENV 2 (FTEST 5) #S(SB-KERNEL:LEXENV :FUNS NIL
:VARS NIL :BLOCKS NIL :TAGS NIL :TYPE-RESTRICTIONS NIL :LAMBDA NIL
:CLEANUP NIL :HANDLED-CONDITIONS NIL :POLICY ((SPEED . 1) (SPACE . 1)
(SAFETY . 1) (SB-EXT:INHIBIT-WARNINGS . 1) (DEBUG . 1)
(COMPILATION-SPEED . 1))))[:EXTERNAL]
3: ("hairy arg processor for SWANK::EVAL-REGION" "(ftest 5)
It seems to me that some internal function doesn't recognize instances
of subclasses of standard-generic-function to be actual functions,
right?
However, I have also tried to distill this into a toy example, but then
I get a totally different error. Here's the code:
(defpackage test
(:use :common-lisp :sb-pcl))
(in-package :test)
(defclass my-generic-function (standard-generic-function)
()
(:metaclass funcallable-standard-class))
(defmethod compute-discriminating-function
((gf my-generic-function))
(let ((dfun (call-next-method)))
(lambda (&rest args)
(apply dfun args))))
(defgeneric funtest (x)
(:generic-function-class my-generic-function))
(defmethod funtest (x)
(+ x x))
And here's the error (when calling (funtest 5)):
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION SB-PCL::GF-ARG-INFO (1)>
when called with arguments
(#<FUNCTION "CLOSURE" {4886F1FD}>).
[Condition of type SIMPLE-ERROR]
Restarts:
0: [ABORT] Abort handling SLIME request.
1: [ABORT] Reduce debugger level (leaving debugger, returning to
toplevel).
2: [TOPLEVEL] Restart at toplevel READ/EVAL/PRINT loop.
Backtrace:
0: ((NO-APPLICABLE-METHOD (T)) #<unavailable argument> #<unavailable
argument> #<STANDARD-GENERIC-FUNCTION SB-PCL::GF-ARG-INFO (1)>
(#<FUNCTION "CLOSURE" {4886F1FD}>))
1: ("XEP for (NO-APPLICABLE-METHOD (T))" 4 #<unavailable argument>
#<unavailable argument> #<STANDARD-GENERIC-FUNCTION SB-PCL::GF-ARG-INFO
(1)> (#<FUNCTION "CLOSURE" {4886F1FD}>))[:EXTERNAL]
2: (SB-PCL::GET-GENERIC-FUN-INFO #<FUNCTION "CLOSURE" {4886F1FD}>)
3: (SB-PCL::CACHE-MISS-VALUES #<FUNCTION "CLOSURE" {4886F1FD}> (5)
SB-PCL::ACCESSOR)
4: (SB-PCL::INITIAL-DFUN #<FUNCTION "CLOSURE" {4886F1FD}> (5))
5: (SB-INT:EVAL-IN-LEXENV 2 (FUNTEST 5) #S(SB-KERNEL:LEXENV :FUNS NIL
:VARS NIL :BLOCKS NIL :TAGS NIL :TYPE-RESTRICTIONS NIL :LAMBDA NIL
:CLEANUP NIL :HANDLED-CONDITIONS NIL :POLICY ((SPEED . 1) (SPACE . 1)
(SAFETY . 1) (SB-EXT:INHIBIT-WARNINGS . 1) (DEBUG . 1)
(COMPILATION-SPEED . 1))))[:EXTERNAL]
6: ("hairy arg processor for SWANK::EVAL-REGION" "(funtest 5)
" T)
I have no idea what's going on here.
> As for your specific use case, it looks a /little/ odd to me, knowing
> nothing at all of the context -- passing an extra argument to the
> system-generated discriminating function? Is it going to expect that?
Yes, the rest of the code prepares the generic function to accept that
extra arg. In fact, this is the only way to sneak in dynamic
information for the actual method selection. The method selection and
combination depends solely on static information otherwise. Maybe there
is a way to do this by replacing the discriminating function
dynamically, but then again this part doesn't seem to work anyway at
the moment.
> (while googling I came across another interesting thread on
> comp.lang.clos: see message-id
> <910923.133523z.12361.lange@...> for the root article).
Yes, that's very interesting and helped me to simplify another
unrelated section of the code. Thanks a lot!
> Oh, one thing you might try to see if it makes a difference: use
> SB-KERNEL:INSTANCE-LAMBDA instead of CL:LAMBDA as your lambda symbol.
> Just a hunch. (If the hunch is right, this is clearly not an optimal
> state of affairs).
This doesn't seem to be defined here in my image.
BTW, I am using SBCL 0.8.12 on Mac OS X.
Pascal
--
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
|