Re: [C++-sig] [Implementation] Calling wrapped functions, converters, policies

David Abrahams <[email protected]>
Newsgroups gmane.comp.lib.boost.langbinding
Message-ID <[email protected]>
I think we need to stop using the term "policy" without qualification.
It gets too confusing.  Every time I do it, I mean CallPolicy (as in
Boost.Python).  I think when you do it you mean ConversionPolicy.  In
fact, why don't we say "[argument|result] [to|from]_xxx converter
generator" for what I called ConversionPolicy?

Daniel Wallin <[email protected]> writes:

> At 14:09 2003-09-17, David Abrahams wrote:
>>Daniel Wallin <[email protected]> writes:
>>
>> >> > struct ContextConcept
>> >> > {
>> >> >     ...
>> >> >     something postcall(something_else);
>> >> > };
>> >> >
>> >> > struct ConverterConcept
>> >> > {
>> >> >     ...
>> >> >     T convert(PolicyConcept::context_type& context);
>> >> > };
>> >>
>> >>This is passing the per-call state into the convert function?  The
>> >>problem I have with this is that the dynamically-registered converter
>> >>implementation doesn't have access to the policy's static type, nor
>> >>presumably to its nested context_type.
>> >
>> > Yes it does; the dynamically-registered converters are implemented as
>> > a default policy
>>
>>You're not making sense here.  The dynamic from-XXX converter
>>implementation does not model the CallPolicy concept, nor, I think,
>>the ConversionPolicy concept.
>
> The functions that does the actual conversion isn't, but the code that
> looks them up and calls them is a model of ConversionPolicy.

Of course.  But it's the function which does the actual conversion
which needs access to the state (or not, depending on the
dynamically-selected converter).

>>It basically comes down to one or two function pointers with a fixed
>>static type for any given C++ target type.  These function pointers
>>get plugged into the static converter at runtime.
>
> Yeah, but they are called from a converter type. Like Boost.Pythons
> rvalue_from_python, pointer_cref_from_python etc..

Sure, but what can that thing do with state, except in the case where
there is no dynamic converter lookup at all?  Not much.

Maybe that's the way you see it?  The default from_xxx converter
generator builds a static converter which uses dynamic lookup and uses
a default kind of state (say, a postcall chain) which is known to all
the dynamically-registered converters, and the others use a kind of
state which is determined at compile time by the static type of the
converter (say, nested in the converter).

>> > which selects the appropriate converter type. There
>> > is no reason the system cannot be aware of the state type:
>> >
>> > struct default_state
>> > {
>> >     postcall_chain* chain;
>> > };
>> >
>> > template<class T>
>> > struct rvalue_converter
>> > {
>> >     T& convert(default_state& state, ...)
>> > };
>>
>>If it's always a postcall chain, what's the point of nesting its type
>>in the CallPolicy?
>
> My point was that it isn't always the postcall chain, it is in the case of
> the default policy though. It isn't a postcall chain in the case of the
> PyUnicode you mentioned earlier.

Actually it could be handled that way... but I suppose that would be
wasteful.

As a matter of fact I think many static from_xxx converter types will
want to wrap the default converter with additional behavior, so their
state will need to include the postcall chain anyway.

> Anyway, we don't need to nest it. It could just be a copy of the policy
> object.
>
> What I'm driving at is that we don't need to make the whole postcall chain
> thing into a special case, it can just as well be handled by the policy system

"Policy system" is getting to be way too-fuzzy a term for me.
But, yeah, I'm all for not having it be a special case.

>> > Note that this is quite possible even if the policy object is copied and
>> > used as state:
>> >
>> > struct default_policy
>> > {
>> >     postcall_chain* chain;
>> >     void postcall(...) { for (postcall_chain* c = chain; c != 0; c = c
>> >     ->next) (*c)(..);
>> > };
>> >
>>
>>Ya lost me here.
>
> Ok, I'll try to describe my vision of this.
>
> We have two concepts, CallPolicy and ConverterPolicy. We hold these policies
> for each wrapped function object, in some type of list. 

Hum.  By the time the function is wrapped, there's no need for
argument from_xxx converter *generators* ("ConverterPolicies")
anymore.  At that point I think we just want a list of argument
from_xxx converters.

But since TMP is functional, it's really moot whether the
determination of the actual converter is early or late.

> It is possible to ask for the ConverterPolicy that can generate a
> converter for a type in the signature at index N.
>
> ConverterPolicy is also a model of CallPolicy

Noooooo!  At least, not the way I understand it.

CallPolicy is the Boost.Python concept that includes pre- and
post-processing of the native interpreter argument tuple.

> with the additional nested template type 'apply' which generates a
> converter type.

In that case, what's the concept you have been calling "CallPolicy?"

> with the signature void f(T0, T1) and Policies we would wind up with
> something like:
>
>    Make copy of policy objects
>
>    Call precall on each of the copied policy objects.
>
>    Fetch converter policy type for index 0.
>    Create converter for index 0.

What's the point of copying the policies in this scheme?  Why not just
store the state in the converter itself?

>    Fetch converter policy type for index 1.
>    Create converter for index 1.
>
>    call ConverterN.match(...), if it fails overload
>    resolution fails.
>
>    f(Converter0.convert(CopiedPolicyObject0),
>    Converter1.convert(CopiedPolicyObject1));
>
>    Call postcall on each of the copied policy objects.
>
> ----- And sample C++ code..
>
>    // the copied policy object, same policy for T0 and T1
>    // so it's just one policy
>    default_policy policy0;

Just one?!  Wow, I'm really confused about that.  What if they each
need their own state?

>    policy0.precall(...);
                     ^^^
What gets passed here?

>    // create converters
>    typename default_policy::apply<T0>::type c0;
>    typename default_policy::apply<T1>::type c1;
>
>    int match_value = 0;
>
>    match_value += c0.match(...);
>    match_value += c1.match(...);
>
>    // do some magic with the match value to choose "best" overload
>
>    f(c0.convert(policy0, ...), c1.convert(policy0, ...));
>
>    policy0.postcall(...);
>
> I'm having a really hard time getting my message across here. :/

I think we're having a problem with terminology.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com



-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.