On Fri, Apr 8, 2011 at 10:53 AM, <span dir="ltr"><<a href="mailto:dherring@tentpost.com">dherring@tentpost.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Jon Anthony wrote:<br>
<div class="im">> Jason E. Aten wrote:<br>
> ;; Since Common Lisp doesn't support method overloading (apparently,<br>
> ;; please correct me if I've misunderstood the comments at the bottom of<br>
> ;; page 194 of Practical Common Lisp),<br>
><br>
> See the lambda list keywords: optional, rest and key. For this simple<br>
> example, optional looks like what you want.<br>
<br>
</div>In CLOS, generic functions distinguish between required and optional<br>
keywords; dispatch only occurs on the required keywords. (I feel I've<br>
misstated the details, but the gist is ok.) Conceptually, all CLOS<br>
dispatch happens at runtime, like virtual functions in C++. (CLOS<br>
implementations may leverage compile-time constants and type information<br>
to achieve static dispatch.)<br>
<br>
C++ static dispatch follows a different ruleset; it can distinguish<br>
between both the arity and type of arguments. For virtual functions, C++<br>
runtime dispatch invokes a function implementation stored in the vtable of<br>
the first argument (left of the dot).<br>
<br>
<br>
Here's one approach for expressing C++ semantics in CL. (Warning: Code<br>
typed over lunch and not tested.)<br>
<br>
// C++<br>
struct S<br>
{<br>
virtual void f(int);<br>
virtual void f(float);<br>
virtual void f(int, float);<br>
...<br>
};<br>
<br><br></blockquote><div><br>Excellent! I was able to get this approach to work very cleanly! Here is the slightly cleaned and tested version of Daniel's outline.<br><br>This seems to provide a very general method. Unless I hear any additional suggestions (which I would be glad to incorporate), I'll make this method the default for wrapping C++ objects with SWIG in the CFFI module.<br>
<br>- Jason<br> <br><br></div></div>;; CL <br>(defstruct S a )<br>
<br>(defgeneric f_1 (s x)<br> (:method ((s S) (x integer)) "method f_1: (s S) (x integer)")<br> (:method ((s S) (x float)) "method f_1: (s S) (x float)"))<br><br>(defgeneric f_2 (s x y)<br> (:method ((s S) (x integer) (y float)) "method f_2 (s S) (x interger) (y float)"))<br>
<br>(declaim (inline f))<br>(defun f (&rest args)<br> "arity dispatch for S::f in C++"<br> (case (length args)<br> (0 (error "function/method f need an object an object to be applied to"))<br> (1 (error "function/method f takes at least 1 argument in addition to an object"))<br>
(2 (apply #'f_1 args))<br> (3 (apply #'f_2 args))<br> (otherwise (error "too many arguments to function f"))))<br><br>(setf mys (make-instance 'S))<br><br>; test arity handling: these should succeed. <br>
(f mys 1)<br>(f mys 1.0)<br>(f mys 1 1.0)<br><br><br>; test arity error conditions too: these should fail. <br>
(f mys)<br>(f)<br>(f mys 1 1 1 )<br><br>;;; success! this all works. Thank you Daniel Herring. right on! <br>
<br>? (setf mys (make-instance 'S))<br>#S(S :a nil)<br><br>? (f mys 1)<br>"method f_1: (s S) (x integer)"<br><br>? (f mys 1.0)<br>"method f_1: (s S) (x float)"<br><br>? (f mys 1 1.0)<br>"method f_2 (s S) (x interger) (y float)"<br>
<br>;;; and it gives errors when caller's arity is wrong: (Horray!)<br><br>? (f mys)<br>> Error: function/method f takes at least 1 argument in addition to an object<br>> While executing: f, in process listener(1).<br>
> Type :POP to abort, :R for a list of available restarts.<br>> Type :? for other options.<br><br><br>1 > (f)<br>> Error: function/method f need an object an object to be applied to<br>> While executing: f, in process listener(1).<br>
> Type :POP to abort, :R for a list of available restarts.<br>> Type :? for other options.<br><br><br>2 > (f mys 1 1 1 )<br>> Error: too many arguments to function f<br>> While executing: f, in process listener(1).<br>
> Type :POP to abort, :R for a list of available restarts.<br>> Type :? for other options.<br><br>