Rag And Bone

January 4, 2008 on 1:43 am | In Hacking, Python |

Usually, when writing bindings for a C library in a high level language, there’s a sweet spot where you have to leave the relative safety of an API similar to the library you are wrapping and the idiomatic correctness dictated by the language itself.

For instance, in the PyClutter bindings a typical clutter.Behaviour constructor is lifted directly from the equivalend function call:

  behaviour = clutter.BehaviourDepth(alpha, -100, 100)

  behaviour = clutter_behaviour_depth_new (alpha, -100, 100);

The ClutterAlpha parameter, though, can ben NULL, so a “keep the API similar to the C equivalent” approach would be:

  behaviour = clutter.BehaviourDepth(None, -100, 100)

  behaviour = clutter_behaviour_depth_new (NULL, -100, 100);

This is, though, different from the “pythonic” approach; as Python has the syntactic sugar to support arguments with default values, the place for those parameters would be at the end of the function call:

  behaviour = clutter.BehaviourDepth(-100, 100)

Correctness issue aside, let’s add the fact that a pythonic approach allows the poor maintainer (yours truly) to drop a lot of hand-written code.

Unfortunately, though, the pythonic approach breaks the API1; more unfortunately, it breaks the API without giving a useful error message: the PyGObject bindings will raise a not very useful

  "TypeError: could not convert parameter 'depth_start' of type 'gint'"

exception when encountering the wrong value type for the argument2.

The question then is: should the idiomatic correctness sway in favour of the language or the underlying library?

Here the blog post ends. I’d like to have an answer for the question, but I’m still undecided; if anyone has some insight, especially Python developers, I’d appreciate a comment

  1. This is not a huge issue as it might seem: the underlying C library has already done that for us []
  2. The error message should be a more useful “could not convert value of type X, and parameter Y requires a value of type Z”, which would require a bit of tinkering in the bindings themselves and it wouldn’t be useful anyway because only the new versions would pick that change up []

6 Comments »

RSS feed for comments on this post. TrackBack URI

  1. Why can’t you do it in the Pythonic way?

    def foo(*args):
    alpha = default_value
    try:
    alpha, spam, eggs = args
    except ValueError:
    try:
    spam, eggs = args
    except ValueError:
    raise TypeError(”foo() takes 2 or 3 arguments (%d given)” % len(args))
    native_foo(alpha, spam, eggs)

    The same could be done in PyC, couldn’t it?

    Comment by Tiago — Friday, January 04 2008 #

  2. Consistency is king! Well, it improves writeability, readability and hence maintainability, anyway. So do you err on the side of language consistence or API consistency?

    The former is useful for people already familiar with the language starting to use the API for the first time, the latter is useful for people starting to use the language for the first time. I would wager people encounter the former a lot more than the latter - we tend to stick with one or two languages but use a large number of different libraries.

    So I would say choose idiomatic correctness, where it makes sense. Having using wxPython, I shudder at the though of using yet another C API expressed as same in Python.

    In this particular situation, could you provided named parameters as a nicer(er) solution, i.e. something like: def BehaviourDepth(ClutterAlpha=None, x=None, y=None): ...?

    This means people can then do clutter.BehaviourDepth(x=-100, y=100), which is perfectly cromulent Python code.

    Comment by Mike Gratton — Friday, January 04 2008 #

  3. […] Read the rest of this great post here […]

    Pingback by Hacking » Blog Archive » Rag And Bone — Friday, January 04 2008 #

  4. Speaking purely for myself, I much, much prefer Pythonic Python bindings to APIs, rather than slavishly implementing the C API. Lots of people won’t ever look at the C API and will just use the Python one. Of course, this does mean that the Python API (a) needs hand-tweaking and (b) needs separate documentation, both of which are bad if you’re the maintainer…

    Comment by Stuart Langridge — Friday, January 04 2008 #

  5. @stuart

    good points. the pygobject bindings tend to err on the python side of things, so in this very case I would be working against them; as for the documentation, you’re very right. I’m puzzled about the lack of documentation tools at least for generating the API reference from the code; in perl we have a module extracting documentation markers and methods and generating perldoc pages, for instance, so I get bare-bones API reference by just binding functions.

    Comment by ebassi — Friday, January 04 2008 #

  6. @mike and tiago:

    yes, I forgot to mention that named parameter passing is already supported, so python developers using it already are perfectly safe.

    Comment by ebassi — Friday, January 04 2008 #

Leave a comment

XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

Show some love for the bulky and voluminous WP-Hashcash!

Powered by WordPress with Pool theme design by Borja Fernandez.
Entries and comments feeds. Valid XHTML and CSS. ^Top^