[Openmcl-devel] Error: The function PRINT is defined as something other than a generic function

Jason E. Aten j.e.aten at gmail.com
Sat Apr 2 22:01:20 PDT 2011


Gary King -- thank you!

Gary Byers --thank you for the pointers and the lucid explanation.

All -- words of warning about SWIG and Common Lisp, as of March 2011:

The reason for my question to begin with was that I was puzzled. I was
puzzled over why the binding generator (SWIG) could possibly be generating
bad code.  I turns out that I was fooled by early small successes with SWIG.
I was fooled into thinking that the SWIG code generator for CFFI was
producing correct code.

In fact after much pounding on it, I realize that SWIG's CFFI module is
incomplete and alpha quality at that.

I've since then corresponded with the current maintainer for SWIG (William
Fulton) and he confirmed that the CFFI module for SWIG hasn't been touched
in 5-6 years, and that it was never very good to begin with, so there's both
bitrot and a partial implementation to begin with to account for.

That said, the cffi.cxx module seems reasonable place to start, and I'm
willing to enhance it. It clearly doesn't handle overloaded C or C++ methods
--those differing only in the number of arguments.  It doesn't seem like it
would be too bad to flesh out the capability, but if anyone knows of a
functional LISP-C++ bridge, I'd certainly be happy not to reinvent the
wheel(!)

So do let me know if you have an alternative for doing Lisp to C++ bindings.

Once issue that I would appreciate commentary on, with regards to binding
C++ and C functions with different numbers of arguments: are generic
functions expensive?  That seemed to be the motivation for not allow
overriding on "ordinary" functions.  Can the compilers not optimize generic
dispatch well?

As far as how to handle functions of the same name but different arity, the
simplest idea (bordering on a hack) would be to use the C++ mangled names
directly, and let the user define aliases using symbols of their choice.
This would be clean and clear, if a bit illegible at first.  The next
easiest thing to do when doing Lisp bindings for two C functions would be to
use defgeneric, which is apparently meant to dispatch to different methods
based on different numbers and values of arguments.  The problem is real for
me, in my C++ code base, as a small example, there are two C functions

char *wchar2ascii(wchar_t
*);

char *wchar2ascii(wchar_t *, unsigned
len);


Currently SWIG's CFFI module generate this two functions in Lisp:

(cffi:defcfun ("_wrap_wchar2ascii__SWIG_0" wchar2ascii) :string
  (arg0 :pointer))

(cl:export 'wchar2ascii)

; and

(cffi:defcfun ("_wrap_wchar2ascii__SWIG_1" wchar2ascii) :string
  (arg0 :pointer)
  (len :unsigned-int))

(cl:export 'wchar2ascii)

Notice that the same symbol is used for both.  Thus the problem.

Anyway, I welcome advice on how to proceed. (Thanks in advance.)

As a side comment, in accordance with that often repeated Greenspun remark
about big projects 'reinventing lisp', I do note that SWIG is internally a
half-done version of Lisp.  Quite amusing as I look through the internals,
to see dynamic typing bolted atop C like that.

Best,
Jason


On Sat, Apr 2, 2011 at 4:25 AM, Gary Byers <gb at clozure.com> wrote:

> <
> http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html
> >
>
> is a chapter from Peter Seibel's book "Practical Common Lisp"; hardcopy of
> that book is available from (among other places) Amazon:
>
> <http://www.amazon.com/Practical-Common-Lisp-Peter-Seibel/dp/1590592395>
>
> If you're just learning CL and CLOS, you'll probably find the answer
> to your question easier to understand if you read that chapter or something
> of similar scope.  A short version of that answer (without the background
> information that a tutorial would provide) is:
>
> 1) CL defines a subtype of FUNCTION - called GENERIC-FUNCTION.
> 2) A GENERIC-FUNCTION can have one or more METHODs associated with it.
> 3) A METHOD (in the simplest case, it can be more complicated than this)
>   associates a set of argument types with a function.  The argument types
>   (classes, mostly) are often called the method's specializers.
>   All of the methods defined on a generic function have to accept (roughly)
>   similar arguments, and only required arguments can be specialized.
> 4) When called with an appropriate number of arguments, a GENERIC-FUNCTION
>   uses the types of the specializable arguments (mostly) to select a set
>   of one or more of the generic function's methods (a set of "applicable
>   methods") and calls them.  (What happens when there's more or less than
>   one applicable method is interesting; read a tutorial.)  The
> GENERIC-FUNCTION
>   doesn't implement any otherwise interesting behavior; its applicable
> methods
>   do.  Methods can be added to (and removed from) a generic function at
> runtime
>   (and certainly during development); there are other ways of doing this,
>   but the most common way of defining a method and adding it to a generic
> function
>   is via the DEFMETHOD macro.
> 5) A non-generic function can't be incrementally augmented in this way.
>  The
>   function named CL:+ is usually not generic, so there's no easy way to
> extend
>   it (to, for instance, allow it to be extended to perform addition on a
> user-defined
>   POLYNOMIAL type.)  CL:+ is often used as a canonical example of a
> non-generic
>   function that could be implemented as a generic function.  There are
> performance
>   and other tradeoffs involved, and (most ? all ?) CL implementations
> define
>   CL:+ as a non-generic function (but it's perfectly legal for an
> implementation
>   to define it generically.)
> 6) DEFMETHOD defines a named METHOD and adds it to the corresponding
> generic function.
>   What that means is that, when it's executed:
>
>   (defmethod name ...)
>
>   looks up the global function definition of NAME.  If there's no global
> definition -
>   if (FBOUNDP NAME) is false - a new GENERIC-FUNCTION is installed as
> NAME's
>   global function definition and the method is added to that generic
> function.
>
>   If the global function definition of NAME is already a generic function,
> the
>   method is added to its set of methods (possibly replacing any
> previously-defined
>   method with the same set of specializers.  And qualifiers, but we're
> ignoring
>   them for now.)
>
>   If neither of these conditions hold - NAME has a global function
> definition but
>   that definition isn't a GENERIC-FUNCTION - then the expansion of
> DEFMETHOD
>   must signal an error.  (There'd be no way to add the method to a
> non-generic
>   function.)
>
> This error is what you're seeing: CL:PRINT is defined as a non-generic
> function,
> and there's no way for the code generated by DEFMETHOD to associate a
> METHOD with
> that non-generic function.  (The standard way of specializing the printer's
> behavior is to define methods on #'CL:PRINT-OBJECT, which is required to be
> a
> GENERIC-FUNCTION.  CL:PRINT and other functions that ... print things ...
> call
> PRINT-OBJECT to handle the details of printing specific types of objects.)
>
> Some of the above is oversimplified to the point that it may not be
> entirely
> accurate, but it's hopefully pretty close, and it's already a lot longer
> than
> I'd intended it to be.
>
>
> On Sat, 2 Apr 2011, Jason E. Aten wrote:
>
>  I'm trying to define a print method for my class, and I'm getting "Error:
>> The function PRINT is defined as something other than a generic function."
>>
>> Below shows the two commands that when issues, reproduce this on Linux
>> x86_64.? What should I try instead?
>>
>> Apologies if this is obvious. I'm new to CLOS, and these classes are auto-
>> generated by SWIG as wrappers for C++ classes.
>>
>> Jason
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20110403/b38ae4a7/attachment.htm>


More information about the Openmcl-devel mailing list