Boost logo

Boost :

From: Stjepan Rajko (stipe_at_[hidden])
Date: 2008-01-10 22:54:06


On Jan 10, 2008 7:58 PM, Joel de Guzman <joel_at_[hidden]> wrote:
> Tobias Schwinger wrote:
> > Joel de Guzman wrote:
> >>
> >> Single function:
> >>
> >> I'm a strong advocate of smaller is better. Modularity matters.
> >> Big classes (or in this case function objects), metaprogram blobs
> >> (i.e. traits), humongous enums, and all such sort of dinosours :-)
> >> are best avoided. They are convenient up to a certain extent and
> >> becomes unmanageable beyond a certain limit.
> >>
> >> In all of my use cases, I have N functions that are provided
> >> elsewhere and I have no control over (e.g. parser functions).
> >> I insist that this is the more common use case. Grouping
> >> them into a single big struct is an unnecessary and cumbersome
> >> step.
> >>
> >> Still, if people insist, I outlined a way to convert the big
> >> function object to smaller 'bound' objects, in another post.
> >> Just bind 'em into smaller function chunks.
> >>
> >
> > I think it's a misconception to assume that a single function object
> > will be inherently big.
>
> It's not about "big". It's about modular vs. monolithic. The
> best designs, IMO, are modular.
>
> > It's just another degree of freedom (namely what to look up) exposed to
> > the user. Whether one can appreciate it seems a matter of taste to me...
> >
> >
> >>> A ---> B: function := L(I): functions[I]()
> >>> B ---> A: transform(cases, L(I): make_pair<I>(bind(function,I())))
> >
> > ...and I happen to prefer the first transform.
>
> I guess that reasoning is due to your thinking that the one
> monolithic automation functor is more common. That's where I
> disagree, vehemently(!). I've got lots of use cases that show
> otherwise. I assert that the more common case is to have as
> input N functions (member/free function pointers, binded
> functions, boost.functions, etc) and the switch_ is used to
> dispatch.
>
> Let me emphasize this to the strongest extent: A single monolithic
> function for the cases in a switch facility is simply and utterly
> wrong, wrong and wrong! :-P If the design stands as it is, I
> better write my own. But it won't get my vote.
>

FWIW, I have a use case in which a single function is used for all the
cases, but it doesn't seem monolithic. Structurally it is very
similar to the example given in the proposed library's documentation -
the case function looks something like this:

// get_port_c behaves similarly to fusion::at_c
// port_t<T> is a run-time polymorphic class derived from port
// the goal of this whole thing is to return a port * (port is the
base class of a run-time polymorphic class hierarchy) from an object
of some type T (T is required to model a certain concept - Port)

template<typename Component>
struct get_port_case
{
    typedef void result_type;
    template<class Case>
    void operator()(Case) const
    {
        ret.reset(new port_t<
            typename result_of::get_port_c<
                Component,
                Case::value,
>::type
>(get_port_c<Case::value>(c)));
    }
    get_port_case(Component& c, std::auto_ptr<port> &ret) : c(c), ret(ret)
    {}
    Component &c;
    std::auto_ptr<port> &ret;
};

It is used like this (the number of ports is known at compile time but
not at "coding time"):

template<typename Component>
std::auto_ptr<port> get_port(Component &c, int port_num)
{
    std::auto_ptr<port> ret;
    typedef mpl::range_c<
        int,
        0,
        mpl::size<
            typename traits_of<Component>::type::ports>
        ::value> range;
    boost::switch_<range>(port_num, detail::get_port_case<Component>(c, ret));
    return ret;
}

"A" seems ideal for this use case. I have trouble seeing how to use
"B" for it (easily) without making it so that the index is passed to
the function object and allowing something like case<range>(...). But
I might not be seeing all the possibilities. How can I implement this
using "B"?

Regardless of this example, if there isn't a "one size fits all"
interface that can be implemented in a lightweight enough fashion to
satisfy everyone,

 * should the Switch library provide both interfaces in separate
functions (even if they are both implemented with their own PP)?; or

 * maybe the submitted library should have a different name/more
clearly stated scope, as Tobias has suggested?

Kudos to all of you for trying so hard at finding a solution for this!

Stjepan


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