Leviathan has asked for the wisdom of the Perl Monks concerning the following question:

Hello fello monks,

I'm writing Perl bindings for Etk, a toolkit for the new Enlightenment Foundation Libraries (link).

The bindings are now almost completed, and I'm now trying to work on an easy to use API for perl.

As an example, in Etk there are different functions to create a button widget:

Etk_Widget *etk_button_new(); Etk_Widget *etk_button_new_with_label(const char *label); Etk_Widget *etk_button_new_from_stock(Etk_Stock_Id stock_id); // Etk_S +tock_Id is an enum

Here is my translation of this into the perl module:

sub new { my $class = shift; my $self = $class->SUPER::new(); if(@_ == 1) { my $thing = shift; $self->{WIDGET} = $thing =~ /\D/ ? Etk::etk_button_new_with_label($thing) : Etk::etk_button_new_from_stock($thing); } else { $self->{WIDGET} = Etk::etk_button_new(); } bless($self, $class); return $self; }

As you can see, I'm trying to stuff different calls inside the same perl method in the spirit of DWIMmery.

Similarly, for example, there's the tree sorting callbacks, it acts differently based on what is passed ar ound. Example:

$tree->Sort( \&sort_func, $asc, $column); # the same routine but without a coderef works differently $tree->Sort(NUMERIC, $asc, $column); # where NUMERIC is a constant, and thus the sorting is done in C to ma +ke it faster and avoid the roundtrip to perl.

Now, problem is that one of the developers of the Etk library is saying that this is a bit confusing for t he user, so I'm asking you fellow monks:

P.S: Anyone interested in checking the code out, it's in CVS in the enlightenment reposit ory accessible from the enlightenment website. It's in the proto/etk-perl module (Note that you need to compi le proto/etk for this to work)

Thanx for your comments and replies.

--
Leviathan.

Replies are listed 'Best First'.
Re: Question about module interface style
by Corion (Patriarch) on Jul 22, 2006 at 15:15 UTC

    Personally, I hate hate hate C-ish libraries when a perlish approach fits much nicer. For example the OpenGL C libraries use something like hungarian notation so the caller can specify what types and how many parameters they pass in:

    glGetLightfv glGetLightiv

    These two functions make no sense in Perl, one is for passing in the number of the light as a floating point number, the other is for passing in the number as an integer number. So, conveniently, there is OpenGL::Simple, which exports only one function and uses Perl (or rather XS) code to determine which function was meant:

    glGetLight

    This is possibly slightly less efficient but doesn't burden me with thinking about the parameter count and types, especially when Perl has to convert to the right types anyway.

    To answer your question, I like how you provide sensible defaults. You might want to make the other, more specialized C functions available too, but maybe not export them, so one can always still override your "smart" code. But as long as your "smart" wrapper even lives in Perl code, people can always look at it and patch it directly. So I say, go for it and reduce the API by Perl dwimmery ;-)

Re: Question about module interface style
by Tuppence (Pilgrim) on Jul 23, 2006 at 01:13 UTC

    Probably the best thing to do here would be to write 2 modules, one a direct port of the C api (so people who know the API already don't have to learn how yours works, but can access the module from perl) and then another module that wraps the low level calls with the API you prefer.

    At the very least, if you get the OO interface 'wrong' someone can use your base module to make a different interface.

    I think the key point I'm trying to make here is that if someone knows the C API for the library you are making available to Perl it should be easy for them to start using your module as well, preferably with as few unexpected changes as possible

Re: Question about module interface style
by Aristotle (Chancellor) on Jul 22, 2006 at 15:12 UTC

    I think you want to take a page or several from Gtk2-Perl. Take a look – gtk+ looks very similar to Etk on the C side as far as I can tell, so it should translate well. Certainly your bound interface as it stands is not at all perlish, while Gtk2-Perl turns the procedural struct-based OO interface of C into the typical invocant-based OO with packages and blessed refs of Perl so that it actually feels like you’re writing OO Perl rather than OO-ish C.

    Makeshifts last the longest.

Re: Question about module interface style
by eyepopslikeamosquito (Archbishop) on Jul 22, 2006 at 22:25 UTC

    Generally, it's a mistake to map a C interface directly to a Perl one. With some careful thought, you can usually do much better by moulding the interface to Perl's strengths. An example that springs to mind is the Win32 Registry API: painful and tedious to use from C, with all those API calls, and all that mucking about checking return codes. By contrast, Win32::TieRegistry is a joy to use: to read from the Registry, you just read from a (tied) hash; to write to the Registry, you simply write to the hash.

    As described in On Interfaces and APIs, the way to go about designing a new API is to "play test" it. Write some tests for it. Start by imagining the perfect interface without worrying about implementation constraints. Then refine it.

      Note that I wrote Win32::TieRegistry and I find that the things I most hate about many XS modules are caused by their attempts to provide a Perl-like interface. If you look under the covers of Win32::TieRegistry you'll find Win32API::Registry which provides a very raw transation of the C API for dealing with the Win32 Registry. There are a few minor niceties added to Win32API::Registry's API, but only ones that I was sure didn't take away any of the possible ways to use the C API and that couldn't be more easily implemented in Perl (actually, some of the niceties are implemented in Perl wrappers inside Win32API::Registry).

      Trying to make Perl-like interfaces in XS is usually a grave mistake, IMO. Even fairly minor steps in that direction tend to lead to code that is hard to write, hard to debug, hard to extend, breaks easily in the face of the simplest of things (a Perl upgrade or any type of Perl magic such as tie), is more likely to have ref-counting bugs, etc.

      Make XS interfaces that are very C-like and expose the full power of the underlying API and then provide Perl wrappers that provide a Perl-like interface. Take Tuppence's advice.

      - tye