guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Future of g-wrap (and guile wrappers in general).


From: Rob Browning
Subject: Re: Future of g-wrap (and guile wrappers in general).
Date: Fri, 31 Aug 2001 15:12:32 -0500
User-agent: Gnus/5.090004 (Oort Gnus v0.04) Emacs/20.7

Matthias Koeppe <address@hidden> writes:

> Looks like something is wrong with the packaging.  I have made the
> relevant part of internals.html available here:
>
>         http://www.math.uni-magdeburg.de/~mkoeppe/guile/swig-guile.html

OK.  Thanks.  Now that I have had a chance to look at that and all of
the other swig docs, I had some questions and comparisons that I think
will help me (and perhaps everyone else) decide if g-wrap should
continue to exist.

My main question is not "what's the better tool", but rather, "Is
g-wrap solving a sufficiently different problem from swig with a
sufficiently different audience that it should continue to exist and
focus on adressing that audience's needs better, or would swig be an
adequate substitute?"

In truth, there is at least some incentive to drop g-wrap and go with
swig.  That way there would be more development effort to go around,
and enhancements to swig (and the guile backend) would benefit other
projects as well.  It would also eliminate an admittedly obscure
dependency for gnucash.

However, at this point I'm kind of leaning toward the conclusion that
at least for now, (a) it's probably less effort to update g-wrap and
continue using it than to switch, and (b), g-wrap may still be of
benefit, providing features that are useful and might not be
appropriate for a more general wrapper tool like swig.

That said, if you've got the time and energy for the following
summary, I'd like to see what you (and everyone else) think(s) about
the following comments, questions, and observations.  Feel free to
ignore any bits you don't have time for, don't know about, etc.  Also
below I describe g-wrap's current state, but I'm very open to, and
interested in alternatives/suggestions/whatever

But first, no matter what I decide.  I'd like to say thanks for all
the swig work.  swig's guile support is *far* better than it was last
time I looked, and it was kind of interesting to see that g-wrap and
swig's guile backend have made some very similar decisions.

Anyway, the following questions and comparisons aren't sorted in any
particular way, but they cover the salient "swig vs. g-wrap issues"
that I've thought of.

  - It looks like swig's handling of the module system is quite good,
    and more up to date than g-wrap's ATM.

  - In some ways swig and g-wrap make similar decisions wrt how to
    handle non-native types (types that don't have a native guile
    representation - i.e. pointers).  Both use smobs, but where swig
    uses one smob type, g-wrap uses two, and if I understand things
    correctly, g-wrap treats the types themselves more as first-class
    objects than swig.

    g-wrap uses two smobs types, one for all the smobs that actually
    carry the C-side pointers -- the actual pointer argument/result
    instances, and one for representing the wrapped types themselves.
    Each instance of a wrapped pointer on the guile side is a smob
    which internally has the C pointer and a pointer to the smob that
    describes wrapped-type.  The type description smob knows the
    string name of the type and some optional type specific
    print/equal/GC functions.  These functions have very similar roles
    to the typical per-smob-type functions.  (So far, we've rarely
    changed these functions from their defaults, but they could be
    handy.)

    For example, if you define a wrapped "pointer" type in g-wrap
    named <gw:Foo*>, then at runtime, a new smob will be created to
    represent the type, and it will be bound to an actual guile
    variable named <gw:Foo*> (let's ignore the naming convention for
    the moment -- it may or may not be the best one).  Then whenever
    g-wrap needs to create an instance of a <gw:Foo*>, either because
    it's a return value from or argument to a wrapped function, it'll
    create a smob of the smob type used to represent all g-wrapped
    pointers, and that smob instance will have an internal pointer to
    the smob representing the <gw:Foo*> type.

    You might wonder why this was done.  By having an actual smob
    representing the wrapped type, and having it bound at the guile
    level to an actual variable, it's possible to do things that are
    often necessary like conversions:

      (gw:coerce-wptr some-obj <gw:Bar*>) -> g-wrapped-Bar*

    efficiently, without any extra hash-table lookup, etc.  You might
    also wonder when this type of thing would really be useful.
    Consider one of our helper functions:

      (gw:map-glist some-func glist-of-bar-ptrs <gw:Bar*>)

    this is a function that will allow you to map over an arbitrary
    <glib:GList*>.  Normally you wouldn't be able to do this, since
    guile has no idea what kind of ptrs are being stored inside the
    glist, but in cases where you know the glist is homogeneous, you
    can use this function to tell gw:map-glist what kind of smobs to
    create and give to some-func.  Though potentially risky (as are
    any C-side type coercions), this has been extremely useful.

    However I'm open to suggestions for better approaches to this
    problem.  In the long run, maybe having g-wrap know about the
    C-side type heirarchy would be safer, but that's a lot more work,
    and still doesn't make things completely safe.  Further, I've
    tended to think of g-wrap as a low-level tool that's sometimes
    enough by itself, but sometimes requires a bit of guile-side code
    to wrap its results up completely elegantly.  Overall this issue
    is still up in the air.

    In any case, it wasn't immediately obvious that swig could handle
    the kind of coercions described above.  Can it do something
    similar?

  - In g-wrap, you can define new types if the current set aren't
    sufficient.  In fact, all of the g-wrap "built in" wrappable types
    are defined using the same g-wrap functions a user would use to
    wrap their own types.  While the syntax is a bit wordy, it's
    extremely flexible, and using the predefined types as an example,
    you can easily define plain pointer types, or fancier types that
    handle a nearly arbitrarily complex conversion from the C type to
    the SCM type and back.  So you can fairly easily define
    <my:foo-scmlist-as-GList-of-Bar*>, etc.

    Though it seems like swig allows something similar, g-wrap fully
    expects that end-users, not just backend designers will be
    defining their own custom types.  Does swig encourage that as
    well, or are users who go crazy with sophisticated typemaps in
    danger of getting themselves in trouble?

  - The disadvantage to the above is that with g-wrap you *do* have to
    define everything.  You have to define a g-wrap wrapped type for
    every pointer type you want <my:Account*>, <my:Foo*>, <my:Bar*>,
    etc.  whereas I think swig handles these pointer types implicitly.
    These defs are usually trivial copy-pastes, but perhaps a
    nuisance.  This could be automated more fairly easily, but right
    now you have to be somewhat painfully explicit.

  - All of the default predefined g-wrap integer types are careful to
    range check their types before conversion.  From the general docs,
    this doesn't seem to be the case for swig.  Is that right?  How
    hard would it be for a user to add their own range-checked types?
    We have cases where either might be appropriate, but we'd rather
    have checked types as the default.  I.e. we'd like to be able to
    choose between <gw:int-u4> and <gw:int-u4-checked> or similar when
    wrapping a function.

  - g-wrap sets up a NULL <-> #f isomorphism for all if its pointer
    types.  So NULL on the C side turns into NULL on the C side and
    vice versa.  This has been quite convenient, and would be a hard
    assumption to excise from the existing g-wrapped apps.

  - From the swig general documentation, I was a little unclear about
    how floating point numbers are handled.  I'd like for the person
    writing the wrappers to be able to be very specific about which
    type(s) they get, and I wasn't sure that was the case in swig.

  - g-wrap has a type called <gw:symbol-as-string> which lets you wrap
    a C function that returns or accepts a string such that these
    values will automatically be converted to/from symbols on the
    guile side.  Not required, but convenient.

  - using g-wrap's type definition mechanism, we were able to define a
    number of string types that make sure that we can properly
    integrate with mixed api's that use both gmalloc and malloc for
    example.  <gw:m-chars-caller-owned>, <gw:m-chars-callee-owned>,
    <gw:g-chars-caller-owned>, and <gw:g-chars-callee-owned>, for
    malloced and gmalloced, caller/callee owned strings respectively.
    This lets you match a C API very closely, specifying exactly
    what's required of the wrappers.

  - g-wrap maps C chars straight to scm chars.  Swig's handling (as
    single character strings on the guile side) seems a little less
    convenient.

  - I was a little confused about how swig handles enumerations.  I've
    posted before about how g-wrap handles them (always return ints,
    accept int or symbol, and define enum-specific converters).  In
    particular, it seemed like swig might the values of the enums to
    be known at swig time rather than compile time.  Any idea if
    that's true?

  - I noticed in the changelog that swig wasn't using scm_bits_t
    because of an older guile compatibility issue.  Shouldn't is use
    scm_bits_t unless it detects an older guile?

  - How good is swig's preprocessor.  Unless it's acutally the *same*
    one you're using to compile your code, relying on it seems a
    little dangerous to me - possibly giving a false sense of
    security.

  - and if you don't rely on the preprocessor, it seems like, given
    swig's comments about %typedefs, that you'd have to maintain
    parallel, manual defs for things like size_t.  In g-wrap, since
    it's spec files are independent of the C code, you have to do that
    anyhow, but there quite a few predefined types for the common
    cases.

  - In swig variable names affect behavior.  i.e. it seems to
    encourage defining "typemaps" that include the variable name so
    that, for example, if you have a typemap named "foo_type *bar",
    any function that has an arg of type foo_type*, named bar will get
    special treatment.  This *really* bothers me.  What if I'm trying
    to wrap an API that just so happens to name its variables of a
    given type using some of the "special" names, but since I haven't
    seen all the included typemaps, I have no idea that that's going
    to invoke special behaviors?

    I think I'd rather see these special behaviors invoked by
    annotations for the function (perhaps in comments).  i.e. either
    in the function's wrapper definition, or if you're wrapping
    headers you can't modify, as a separate statement in the swig spec
    file like "%makeoutputarg foo_func some_arg_name" or similar.  I
    couldn't tell for sure if swig supported that, but if so, it would
    be nice to be able to turn off the arg name based mapping for a
    given swig module, for those of us who are paranoid :>

  - swig handles multiple return values quite well it looks like,
    though it might be nice to be able to specify the handling
    per-function when desired.  OTOH g-wrap doesn't handle multiple
    return values at all yet, and can't automatically handle "OUTPUT"
    pointer args like swig can.  (Actually, I suppose swig might
    already allow you to switch multiple-return methods within a file,
    dunno...)

  - g-wrap tries to support the idea of shared independent modules.
    i.e. at least originally, it was intended that someone should be
    able to use g-wrap to enable (use-modules (opengl)) or
    (use-modules (glib)) and have other, completely independently
    created g-wrapped modules use opengl and glib and pass wrapped
    pointers like <glib:Glist*> around among themselves safely.  Does
    swig also handle that kind of thing?  It looked like it might,
    given libswigguile.

  - swig handles structs and variables whereas g-wrap doesn't at all
    yet, at least not with any kind of automation.  You'd have to
    create C-side accessors yourself and wrap those ATM.

Thanks

-- 
Rob Browning
rlb @defaultvalue.org, @linuxdevel.com, and @debian.org
Previously @cs.utexas.edu
GPG=1C58 8B2C FB5E 3F64 EA5C  64AE 78FE E5FE F0CB A0AD



reply via email to

[Prev in Thread] Current Thread [Next in Thread]