[C++-sig] Re: Interest in luabind

David Abrahams dave at boost-consulting.com
Sun Jun 29 00:34:30 CEST 2003

"Daniel Wallin" <dalwan01 at student.umu.se> writes:

>> >> > Need to think about this some more. It's no special
>> >> > case in BPL though, it's just another type of
>> >> > instance_holder, correct?
>> >>
>> >> Not only that.  It's an issue of where the instance
>> >> holder gets constructed.  In this case it is
>> >> constructed directly in the storage for the Python
>> >> object.
>> >
>> > Right, that's pretty cool.
>> Yeah, but I doubt it's saving much, and it leads to much
>> complication (c.f. instance_new and instance_dealloc in
>> libs/python/src/object/class.cpp).  If objects are
>> getting created and destroyed a *lot* it could reduce
>> fragmentation and increase locality... but as I said I
>> have big doubts.
> Yeah, fragmentation issues can always be solved with pool
> allocation. 

But locality can't, for what that's worth.  Frankly I think
it's not worth much.

> Is the complexity only due to value-holders, or just
> different kind of holders? Seems to me (without having
> looked at instance_new/instance_dealloc yet..) like you
> would need the same allocation routines for
> pointer-holders as well.

I'm trying to tell you it has nothing to do with the how the
holders contain their data [though see below]; it's about
how/where the holders themselves are constructed.

The object model is something like this: every wrapped class
instance contains an endogenous linked list of holders (to
handle multiple inheritance from wrapped classes) and some
raw storage to use for holder allocation.  A class wrapper
knows the size and alignment of its default holder, so
usually the holder will be allocated right in the raw
storage.  If the holder turns out to be too big for that
storage, e.g. the default holder contains an auto_ptr<T> but
for some reason a value_holder<T> is used, or a
value_holder<U> is used where U is derived from T, then the
holder will be dynamically allocated instead.  Additional
holders in MI situations can also end up being dynamically
allocated.  Arranging for the extra storage in the Python
object means we have to fool Python into thinking the
objects are variable-length (like a tuple), and incurs a few
other complications.

Well, OK, actually I suppose the argument forwarding problem
(http://tinyurl.com/fist) causes a lot of additional
complexity because references need to be passed through
reference_wrapper<T> arguments, and that would go away if
there were no value_holders.  I barely even notice that
anymore, since it was part of BPLv1... but now that you
mention it, value_holder is probably causing more
complication in the code than in-place holder allocation.
Eliminating both might be a huge simplification.
Additionally, it might become possible to convert nearly any
object to nearly any kind of smart pointer.  value_holders
impose some real limitations on usability.

>> >> The to-python converter that gets registered for
>> >> auto_ptr<T> by using it in a class<T, std::auto_ptr<T>,
>> >> ... > or by using
>> >> register_pointer_to_python<std::auto_ptr<T> > knows what
>> >> to do.
>> >
>> > Ah, right. It's pretty nice to be able to hold the instances
>> > in different kind of holders.
>> Yeah.
>> Note also that shared_ptr is "magic", in that any wrapped
>> T can be converted to shared_ptr<T> regardless of holder,
>> and the resulting shared_ptr<T> can be converted back to
>> the original Python object (not just a new one sharing
>> the same C++ object).
> Ok. I noticed that while browsing the code. The custom
> deleter is a powerful tool. :)

Yeah, Peter's design really is beautiful.

>> >> > and even the
>> >> > ones that doesn't can still be used in different contexts.
>> >> > ('result' when doing C++ -> lua, and '_N' when doing lua ->
>> >> > C++).
>> >>
>> >> How is that *not* a case of bidirectionality?
>> >
>> > :) It is, my fault. I meant it could be used in different
>> > contexts with the same direction, it should read something
>> > like: 'result' when calling a C++ function, '_N' when
>> > calling a lua function.
>> >
>> >> That rule makes me nervous, because the terms are
>> >> backwards when calling lua/python from C++.  Do people
>> >> get confused?
>> >
>> > I don't think they do, I don't think anyone has reported any
>> > problems with it yet. It's backwards for a reason though,
>> > and it's pretty clear when to use which placeholder. (except
>> > in some special cases, where documentation helps).
>> OK.  Maybe we could allow a default argument which would
>> "just work" for these cases.  Another option is "_", which
>> is used in MPL for something similar.
> Sure, that would be nice. You can also introduce additional
> placeholder aliases for the cases where '_N' and 'result'
> doesn't fit very well.

My point is that I'm trying to get away from a scenario
where users have to think about which choice is right, when
the context dictates that there can only be one right
choice.  Adding different names for the choices doesn't
help with that problem.  This is a minor nit.

It sounds like we're converging quite rapidly.  What other
issues do we need to deal with?

Dave Abrahams
Boost Consulting

More information about the Cplusplus-sig mailing list