Boost logo

Boost :

Subject: Re: [boost] [parameter] some extensions to Boost.Parameter
From: Stjepan Rajko (stipe_at_[hidden])
Date: 2008-10-28 23:45:57


On Tue, Oct 28, 2008 at 2:08 PM, David Abrahams <dave_at_[hidden]> wrote:
>
> on Tue Oct 28 2008, "Stjepan Rajko" <stipe-AT-asu.edu> wrote:
>
>> I have found these extensions useful when
>> using ArgumentPacks directly rather than using Boost.Parameter macros
>> like BOOST_PARAMETER_FUNCTION, BOOST_PARAMETER_CONSTRUCTOR,... (I am
>> using the library in this particular way because of reduced compile
>> times
>
> That's a bit of a surprise. What kind of difference in compile time are
> you seeing?
>

Nothing too dramatic. In the following experiment:
http://article.gmane.org/gmane.comp.lib.boost.devel/178703

... the results for a simple test scenario gave the following times:
user: [test_parameter_compilation.o] 0.000195
system: [test_parameter_compilation.o] 0.000030
user: [test_parameter_dispatch_compilation.o] 0.000555
system: [test_parameter_dispatch_compilation.o] 0.000041

test_parameter_compilation corresponds to using ArgumentPacks
directly, and test_parameter_dispatch_compilation uses
BOOST_PARAMETER_CONSTRUCTOR (perhaps for BOOST_PARAMETER_FUN the
difference is even smaller or non-existent)

>> and (IMO) cleaner library code
>
> Could you show some examples?
>

Sure. My use case is a GUI library that tries to make it easy to
implement new widgets. Widgets can be put together by stacking
behaviors in an inheritance chain. For example, a button uses the
following base class:

class button;

typedef
    view::active_colored<
        view::solid_background<
            view::clickable<button,
                view::positioned<>
> > > button_base_type;

- each of the view:: templates listed adds a behavior to the button
widget, and they are implemented by inheriting the next behavior in
the chain (in this case, button will inherit active_colored which will
inherit solid_background which will inherit clickable which will
inherit positioned...). Here is the button constructor:

class button : public button_base_type
{
public:
    typedef button_base_type base_type;

    template<typename ArgumentPack>
    button(const ArgumentPack &args)
        : button_base_type(args)
    {}
...

I.e., the constructor takes an ArgumentPack and forwards it to its
base class. The base class will perhaps pick off some arguments and
forward the pack to its base, etc. For example, solid_background does
this:

template<typename BaseView=base>
class solid_background : public BaseView
{
public:
    typedef BaseView base_type;

    template<typename ArgumentPack>
    solid_background(const ArgumentPack &args)
        : base_type(args)
        , m_background_color(args[_background])
    {}
...

I have found that the direct use of ArgumentPacks makes this
inheritance-chaining design quite nice/clean to implement. AFAICT,
using the macro-based interface would have required two classes per
view/behavior (an implementation class, and a class that uses
BOOST_PARAMETER_CONSTRUCTOR) - this is because any of these classes
can be the top-level class. That alone was reason enough for me not
to investigate that route further - I'm not sure whether any
difficulty would arise from having to specify that a class can receive
a parameter intended for it, or intended for the base class.

> Answers to these two questions could help me evaluate the merits of
> integrating this functionality into the library.
>
>> (although user-side code takes a slight hit)).
>
> That shouldn't be necessary, even if you forego the macros.
>

I think I'm stuck with requiring double parenthesis, and I don't know
how to take advantage of, e.g., deduced parameters.

>>
>> Here are brief descriptions of the extensions:
>>
>> *1* Keywords/Tags with fixed types
>> These are intended for keywords/tags that are always associated with a
>> certain type of argument. operator= of a fixed-type keyword always
>> return a tagged argument whose value_type is the fixed type.
>>
>> This has the benefit of moving any type conversions to the call site,
>
> Might be interesting if we can integrate that into the macros for the
> cases when you specify a fixed type. This sounds vaguely similar to
> what we have to do for the Python binding functionality, except that we
> do the "type fixing" post-facto.
>

I think this would be relatively easy and safe (in a non-breaking
change sense) to add in.

[...]

>>
>> BOOST_PARAMETER_TYPED_NAME_WDEFAULT(label,const std::string,"")
>>
>> If a ArgumentPack args does not contain an explicit value for _label,
>> args[_label] will return std::string(""). I'm not sure what the right
>> response to e.g., args[label|"something"] should be.
>
> Compilation error?

Perhaps. I think the alternative that Andrey Semashev suggested is
also interesting, where "something" is chosen if the label is not
explicitly provided. That would allow the default-default
functionality to also be useful in scenarios where the default value
is fixed "almost always".

>
>> *3* Make ArgumentPacks constructible from other ArgumentPacks.
>
> Aren't they already?
>
>> I basically added a constructor to arg_list that does allows something
>> like the following:
>>
>> // this will return an appropriate arg_list type, containing four tagged_args
>> // the four tags are all typed (*1*) and with default default values(*2*)
>> typedef argument_pack<tag::label, tag::size, tag::position,
>> tag::background>::type
>> argument_pack_type;
>>
>> window(const argument_pack_type &args);
>>
>> In the above case, e.g., window(( _label="label",
>> _size=size_type(100,100) )) would call window with default-default
>> values for position and background.
>>
>> The benefit here is that the implementation of window doesn't need to
>> be templated (which is helpful in some cases), and you don't need to
>> write any forwarding functions (or use BOOST_PARAMETER_FUN).
>
> Ohhh.... so you're saying any two argument packs with the same keywords
> and types would be inter-convertible, regardless of argument order?
> That makes some sense.
>

Yes - a source pack could be converted to a target pack type as long
as the source contains a superset of the tags needed for the target
(or any missing tags have a default-default value).

>> *4* Overloading operator() for typed keywords
>>
>> Instead of writing, e.g.:
>> window (( _size=size_type(100,100), _position=position_type(0,0) ))
>> , we can write
>> window (( _size(100,100), _position(0,0) ))
>
> Pretty cool.
>
> This looks like it overlaps with deduced parameters a lot, though.
>

Yes, there is overlap. If deduced parameters were available (are
they, without the macros?), you could do:

window (( size_type(100,100), position_type(0,0) ))

except `window (( _size(100,100), _position(0,0) ))` would also work
when size_type and position_type are the same type.

>>
>> Please let me know if there is any interest.
>
> I'd have to see what Daniel thinks. It would also be interesting to
> know if anyone else in the community has wanted this functionality.
>

Thanks for taking a look!

Best,

Stjepan


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk