To over simplify a little, in Smalltalk style OO I can
dynamically handle unimplemented methods by doing something useful with
the #doesNotUnderstand message. CLOS has the NO-APPLICABLE-METHOD generic
function, but the original generic function (with the unimplemented
method) has to at least exist.
Let's say I want write a wrapper for something like gtk-server
(http://www.turtle.dds.nl/gtk-server/index.html: basically it provides a
character stream, interpretive interface to GTK).
What's the most basic scaffolding I can build to provide a CLOS interface
to the GTK framework, assuming I want to do as much as possible at
runtime (looking up and providing proxies for classes, objects, methods,
etc.)
Matt
--
"You do not really understand something unless you can
explain it to your grandmother." — Albert Einstein.
Matthew D Swank wrote:
> To over simplify a little, in Smalltalk style OO I can
> dynamically handle unimplemented methods by doing something useful with
> the #doesNotUnderstand message. CLOS has the NO-APPLICABLE-METHOD generic
> function, but the original generic function (with the unimplemented
> method) has to at least exist.
>
This is not correct, all you need to attempt a method dispatch is the
symbol,
(defclass test () ())
(defmethod testit ((obj test)) 10)
CL-USER 1 > (defparameter test (make-instance 'test))
TEST
CL-USER 2 > (testit test)
10
CL-USER 3 > (funcall 'testit test)
10
CL-USER 4 > (handler-case
(funcall 'bogus-method test)
(error (c) (type-of c)))
UNDEFINED-FUNCTION
CL-USER 5 >
> Let's say I want write a wrapper for something like gtk-server
> (http://www.turtle.dds.nl/gtk-server/index.html: basically it provides a
> character stream, interpretive interface to GTK).
>
> What's the most basic scaffolding I can build to provide a CLOS interface
> to the GTK framework, assuming I want to do as much as possible at
> runtime (looking up and providing proxies for classes, objects, methods,
> etc.)
>
> Matt
>
>
Wade Humeniuk <··················@telus.net> writes:
> Matthew D Swank wrote:
>> To over simplify a little, in Smalltalk style OO I can
>> dynamically handle unimplemented methods by doing something useful with
>> the #doesNotUnderstand message. CLOS has the NO-APPLICABLE-METHOD generic
>> function, but the original generic function (with the unimplemented
>> method) has to at least exist.
>
> This is not correct, all you need to attempt a method dispatch is the
> symbol,
>
> (defclass test () ())
>
> (defmethod testit ((obj test)) 10)
>
> CL-USER 1 > (defparameter test (make-instance 'test))
> TEST
>
> CL-USER 2 > (testit test)
> 10
>
> CL-USER 3 > (funcall 'testit test)
> 10
>
> CL-USER 4 > (handler-case
> (funcall 'bogus-method test)
> (error (c) (type-of c)))
> UNDEFINED-FUNCTION
Which is to say that in lisp, you have a #doesNotUnderstand for ALL
function calls, not only for messages.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Cats meow out of angst
"Thumbs! If only we had thumbs!
We could break so much!"
Pascal Bourguignon wrote:
> Wade Humeniuk <··················@telus.net> writes:
>
>
>>Matthew D Swank wrote:
>>
>>>To over simplify a little, in Smalltalk style OO I can
>>>dynamically handle unimplemented methods by doing something useful with
>>>the #doesNotUnderstand message. CLOS has the NO-APPLICABLE-METHOD generic
>>>function, but the original generic function (with the unimplemented
>>>method) has to at least exist.
>>
>>This is not correct, all you need to attempt a method dispatch is the
>>symbol,
>>
>>(defclass test () ())
>>
>>(defmethod testit ((obj test)) 10)
>>
>>CL-USER 1 > (defparameter test (make-instance 'test))
>>TEST
>>
>>CL-USER 2 > (testit test)
>>10
>>
>>CL-USER 3 > (funcall 'testit test)
>>10
>>
>>CL-USER 4 > (handler-case
>> (funcall 'bogus-method test)
>> (error (c) (type-of c)))
>>UNDEFINED-FUNCTION
>
>
> Which is to say that in lisp, you have a #doesNotUnderstand for ALL
> function calls, not only for messages.
That's misleading. The error object doesn't contain enough information
to do something useful with this error - it lacks the arguments that
were passed to the function. Furthermore, you cannot provide
class-specific behavior for handling this error.
Smalltalk's #doesNotUnderstand is more flexible in this regard because
each class can provide its own method for #doesNotUnderstand. Since it
is a single-dispatch language, it is always clear who is responsible for
handling #doesNotUnderstand, and since the arguments are available,
other methods can be called to resolve the lack of the method in question.
Pascal
--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
On Thu, 15 Dec 2005 09:39:15 +0100, Pascal Costanza wrote:
> Pascal Bourguignon wrote:
>> Wade Humeniuk <··················@telus.net> writes:
>>
>>>CL-USER 4 > (handler-case
>>> (funcall 'bogus-method test)
>>> (error (c) (type-of c)))
>>>UNDEFINED-FUNCTION
>>
>>
>> Which is to say that in lisp, you have a #doesNotUnderstand for ALL
>> function calls, not only for messages.
>
> That's misleading. The error object doesn't contain enough information
> to do something useful with this error - it lacks the arguments that
> were passed to the function. Furthermore, you cannot provide
> class-specific behavior for handling this error.
This brings up an interesting point though. Are there any hooks into the
default function dispatch that would allow more information about the
function application to be returned as a condition (w/o shadowing
funcall/apply)?
Matt
--
"You do not really understand something unless you can
explain it to your grandmother." — Albert Einstein.
Matthew D Swank wrote:
> On Thu, 15 Dec 2005 09:39:15 +0100, Pascal Costanza wrote:
>
>
>>Pascal Bourguignon wrote:
>>
>>>Wade Humeniuk <··················@telus.net> writes:
>>>
>>>
>>>>CL-USER 4 > (handler-case
>>>> (funcall 'bogus-method test)
>>>> (error (c) (type-of c)))
>>>>UNDEFINED-FUNCTION
>>>
>>>
>>>Which is to say that in lisp, you have a #doesNotUnderstand for ALL
>>>function calls, not only for messages.
>>
>>That's misleading. The error object doesn't contain enough information
>>to do something useful with this error - it lacks the arguments that
>>were passed to the function. Furthermore, you cannot provide
>>class-specific behavior for handling this error.
>
> This brings up an interesting point though. Are there any hooks into the
> default function dispatch that would allow more information about the
> function application to be returned as a condition (w/o shadowing
> funcall/apply)?
Not in ANSI CL, AFAICT. There's only no-applicable-method.
Interestingly, according to 11.1.2.1.2 Constraints on the COMMON-LISP
Package for Conforming Programs, you are not allowed to define any
method on that function.
So you have to define your own subclass of standard-generic-function in
order to be able to hook into the dispatch mechanism. (or you hack your
own version of CL from one of the open source implementations ;)
Pascal
--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
> Interestingly, according to 11.1.2.1.2 Constraints on the COMMON-LISP
> Package for Conforming Programs, you are not allowed to define any
Interestingly NO-APPLICABLE-METHOD says that programmers _are_ allowed
to define methods for it, and given that you can't subclass
STANDARD-GENERIC-FUNCTION with plain ANSI (I think/hope) it "obviously"
implies a weaker restriction then that... ;-)
Oodles of fun.
Cheers,
-- Nikodemus Siivola
On 2005-12-15 17:27:58 -0500, "Nikodemus Siivola"
<·········@random-state.net> said:
>>
>
> Interestingly NO-APPLICABLE-METHOD says that programmers _are_ allowed
> to define methods for it, and given that you can't subclass
> STANDARD-GENERIC-FUNCTION with plain ANSI (I think/hope) it "obviously"
> implies a weaker restriction then that... ;-)
>
> Oodles of fun.
From the hyperspec (emphasis added of course):
"11.1.2.1.2 Constraints on the COMMON-LISP Package for Conforming Programs
Except where explicitly allowed, the consequences are undefined if any
of the following actions are performed on an external symbol of the
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
COMMON-LISP package:"
and, as you point out, no-applicable-method explicitly allows methods
to be defined.
With regard to Matt's original question, I know nothing about gtk, but
this seems to work in lispworks, openmcl, sbcl and abcl...
(defclass class-with-no-gtk-methods-specialized-on-it () ())
(defvar *my-instance-with-no-gtk-methods* (make-instance
'class-with-no-gtk-methods-specialized-on-it))
(defgeneric some-gtk-wrapper (an-object))
(defmethod no-applicable-method ((a-generic-function (eql
#'some-gtk-wrapper)) &rest gf-args)
(look-up-appropriate-gtk-method-for-instance (first gf-args)))
(defun look-up-appropriate-gtk-method-for-instance (an-object)
(format t "I'm looking up the right gtk method for the object ~a, an
instance of the class ~a, really I am." an-object (class-of an-object)))
CL-USER 199 > (some-gtk-wrapper *my-instance-with-no-gtk-methods*)
I'm looking up the right gtk method for the object
#<CLASS-WITH-NO-GTK-METHODS-SPECIALIZED-ON-IT 10C65FB3>, an instance of
the class #<STANDARD-CLASS CLASS-WITH-NO-GTK-METHODS-SPECIALIZED-ON-IT
10C4A003>, really I am.
NIL
...but breaks in ecl:
> (load "/raflisp/no-applicable-method.lisp")
;;; Loading "/raflisp/no-applicable-method.lisp"
;;; Warning: NO-APPLICABLE-METHOD is being redefined.
"/raflisp/no-applicable-method.lisp"
> (some-gtk-wrapper *my-instance-with-no-gtk-methods*)
I'm looking up the right gtk method for the object NIL, an instance of
the class #<The BUILT-IN-CLASS NULL>, really I am.The function NIL is
undefined.
Broken at EVAL.
>>
regards,
Ralph
On Fri, 16 Dec 2005 03:27:02 +0000, Raffael Cavallaro wrote:
> With regard to Matt's original question,
...
> (defclass class-with-no-gtk-methods-specialized-on-it () ())
>
> (defvar *my-instance-with-no-gtk-methods* (make-instance
> 'class-with-no-gtk-methods-specialized-on-it))
>
> (defgeneric some-gtk-wrapper (an-object))
>
> (defmethod no-applicable-method ((a-generic-function (eql
> #'some-gtk-wrapper)) &rest gf-args)
> (look-up-appropriate-gtk-method-for-instance (first gf-args)))
>
> (defun look-up-appropriate-gtk-method-for-instance (an-object)
> (format t "I'm looking up the right gtk method for the object ~a, an
> instance of the class ~a, really I am." an-object (class-of an-object)))
>
Yes, this is the standard CLOS-y way of doing this, but I either need a
wrapper generic function for every library function I wrap, or
make the wrapper function a "send" or "apply" verb, with the first
argument being the target function name.
btw thanks to you and everyone else for their comments. Common Lisp
never disappoints in the multiplicity of different ways to do something
dynamic.
Matt
--
"You do not really understand something unless you can
explain it to your grandmother." — Albert Einstein.
On 2005-12-16 02:22:46 -0500, Matthew D Swank
<·······································@c.net> said:
>
> or
> make the wrapper function a "send" or "apply" verb, with the first
> argument being the target function name.
This would be the way to go imho, unless there's a way to auto-generate
the many wrapper gfs from headers or somesuch.
regards,
Ralph
Raffael Cavallaro schrieb:
> On 2005-12-15 17:27:58 -0500, "Nikodemus Siivola"
> <·········@random-state.net> said:
>
> >>
> >
> > Interestingly NO-APPLICABLE-METHOD says that programmers _are_ allowed
> > to define methods for it, and given that you can't subclass
> > STANDARD-GENERIC-FUNCTION with plain ANSI (I think/hope) it "obviously"
> > implies a weaker restriction then that... ;-)
> >
> With regard to Matt's original question, I know nothing about gtk, but
> this seems to work in lispworks, openmcl, sbcl and abcl...
> [...]
> ...but breaks in ecl:
Contrary to the standard, ECL did not expect NO-APPLICABLE-METHOD to
return. This has been fixed in the CVS tree.
Juanjo
On Thu, 15 Dec 2005 17:58:36 +0100, Pascal Costanza wrote:
> Matthew D Swank wrote:
>> Are there any hooks into the default function dispatch that would allow
>> more information about the function application to be returned as a
>> condition (w/o shadowing funcall/apply)?
>
> Not in ANSI CL, AFAICT. There's only no-applicable-method.
>
Well this works in CLISP, but it doesn't seem very portable (it would
require an implementation to implement a default use-value restart for
function-cells).
(defun silly-dispatch (name args)
(list name (apply #'+ args)))
(defmacro with-alt-dispatch (&body forms)
`(handler-bind ((undefined-function
#'(lambda (c)
(use-value #'(lambda (&rest args)
(silly-dispatch (cell-error-name c)
args))))))
,@forms))
(with-alt-dispatch (list (* 2 2) (- 7 3) (unbound-fun 2 3 4 5)))
==> (4 4 (unbound-fun 14))
--
"You do not really understand something unless you can
explain it to your grandmother." — Albert Einstein.
Matthew D Swank wrote:
> To over simplify a little, in Smalltalk style OO I can
> dynamically handle unimplemented methods by doing something useful with
> the #doesNotUnderstand message. CLOS has the NO-APPLICABLE-METHOD generic
> function, but the original generic function (with the unimplemented
> method) has to at least exist.
I am convinced that something like this isn't possible in plain CLOS.
This is the one downside of the fact that methods belong to generic
functions and not to classes.
> Let's say I want write a wrapper for something like gtk-server
> (http://www.turtle.dds.nl/gtk-server/index.html: basically it provides a
> character stream, interpretive interface to GTK).
>
> What's the most basic scaffolding I can build to provide a CLOS interface
> to the GTK framework, assuming I want to do as much as possible at
> runtime (looking up and providing proxies for classes, objects, methods,
> etc.)
I have sketched an implementation of delegation (i.e., objects
forwarding generic function calls to other objects with proper rebinding
of the arguments) using the CLOS MOP, but this fails on a number of CLOS
MOP implementations. It's also quite tricky.
I can imagine the following workaround for your case:
- define your own generic function class:
(defclass forwarding-generic-function (standard-generic-function)
())
- Override no-applicable-method:
(defmethod no-applicable-method ((gf forwarding-generic-function) ...)
...)
-> There you can decide how to forward function calls to other objects.
- Declare all your generic functions to be forward-generic-functions.
This means that all generic functions have to be introduced via defgeneric.
- This means that you cannot affect generic functions of other
libraries. However, I guess that shadowing and redefining them
appropriately should do the job.
Of course, this is all not tested.
Pascal
--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/