Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2004-11-13 10:02:16


"Thorsten Ottosen" <nesotto_at_[hidden]> writes:

> "David Abrahams" <dave_at_[hidden]> wrote in message
> news:uekiyo6n5.fsf_at_boost-consulting.com...
> | "Thorsten Ottosen" <nesotto_at_[hidden]> writes:
> |
> | > I think it should not be accepted. My main motivation is that I
> | > think it promotes an unsound growth in function interfaces.
> |
> | Like having support for derivation promotes an unsound reliance on
> | implementation inheritance and support for operators promotes abuse
> | of operator overloading?
> |
> | Features don't promote practices.
>
> I'm not sure I agree. I can just imagine all those C++ programmers
> who now thinks its cool to have functions with +5
> parameters--afterall a respected library like boost has this cool
> library that allows it.

The C++ language already allows it. Did you complain about the fact
that Boost.Function or Boost.Bind or Boost.Python or Boost.Type Traits
supports more than five parameters? If not, why not?

> So the fact that the feature exists and is part of boost will send
> the wrong message IMO.

The library isn't designed to allow you to use lots of parameters.
It's designed to make code more readable and to allow you to take
advantage of default arguments without regard to parameter order.

> | > I also miss a comparison of other techniques (eg. bgl_named_params,
> | > named_constructor_pattern)
> |
> | I don't know about the latter. Never heard of it. But I'm guessing
> | you're talking about something like:
> |
> | f(slew_is(.799), score_is(55))
> |
> | If so, either it allows arbitrary parameter ordering and aside from
> | the use of () instead of = its advantages are equivalent to those of
> | our library, or it does not, and our library offers the advantage of
> | freeing the user/reader/maintainer from having to remember parameter
> | order.
>
> yeah, doesn't the bgl solution do that too?

Yes, but it has associated disadvantages as well, which I explained
in my last posting.

> | > to do the same and an good explanation why this approach is
> | > superior.
> |
> | This approach is superior to bgl_named_params in part because it
> | avoids undue coupling and dependency in a library design.
>
> | While writing this book, we reconsidered the interface used for named
> | function parameter support. With a little experimentation we
> | discovered that it's possible to provide the ideal syntax by using
> | keyword objects with overloaded assignment operators:
> |
> | f(slew = .799, name = "z");
> |
> | Not only is this syntax nicer for users, but adding a new parameter
> | name is easy for the writer of the library containing f, and it
> | doesn't cause any coupling.
>
> ok, I don't see the simple object.set_XX() to cause any coupling either.

It doesn't cause any coupling. But it's uglier than what we're doing,
and it requires state, and provides no advantages. One major problem
with state (aside from stylistic concerns which I also consider valid)
is:

     f(table = create_a_table(), name = "boxes")

if create_a_table returns a vector, it can be passed by reference all
the way through to f's implementation. With
obj.set_table(create_a_table()), you have to store a copy of the
vector.

> | > Let me elaborate.
> | >
> | > 1. Clearly, this is not nice
> | >
> | > window* w = new_window("alert", true, true, false, 77, 65);
> |
> | True, but sometimes it is appropriate. Even then, you only need two
> | parameters whose order is not obviously dictated by function to
> | justify the use of a named parameter interface:
> |
> | paint(hue = 1071, luminance = 10)
> |
> | vs.
> |
> | paint(1071, 10)
>
> again, you could just say
>
> painter p;
> p.set_hue( 1071 );
> p.set_luminance( 10 );
> p.paint();

Yes, but it's ugly, stateful, and comparitively easy to misuse. And
it's not even the moral equivalent of having named parameters, as far
as I can tell. You're worried about "making it possible" to write
functions with >5 parameters, but a class with >5 setter functions
that isn't really meant to act like an ordinary class but instead as a
poor man's substitute for a function with named parameters is surely
worse than just having the feature!

> | > However, the amount of work needed to code parameters for this is
> | > quite large.
> |
> | Really? Did you compare how much work it would be to use
> | BOOST_NAMED_PARAMS_FUN vs. what you're suggesting below?
>
> I think I read the tutorial and that function was not mentioned in there, was
> it?

That macro is described in section 6.

> | > A simple, effective way is just to do it like this:
> | >
> | > window* w = new_window("alert");
> | > w->set_resizable( true );
> | > w->set_height( 77 );
> | > ....
> |
> | How would you apply that idiom to the algorithms of the Boost Graph
> | Library?
>
> make a class like this:
>
> class bellman_ford_shortest_paths_executor
> {
> // one variable for each paramter, possibly using optional to save
> // performance
> void set_weight_map( weight_map& );
> void set_distance_map( distance_map& );
> ...
> execute( Graph& g, size_t n );
> };

That has all the problems mentioned earlier. It's ugly and stateful,
it doesn't say what it means, and it's easy to misuse.

> Depending on how it is designed, you can also pass such an object
> around wihout relying on function<> and you might be able to query
> about the execution context.
>
> Alternatively, some of the last N optional parameters should be
> encapsulated in some new concept; it might even turn out that this
> concept can be used many places and will give the library an
> increased abstraction-level.

I've no clue what you're referring to in the first of those two
paragraphs. I understand the second one, but w.r.t. to both of them
it's no fair making arguments based on hypotheticals. Come up with
concrete examples if you want to pursue these.

> | > and you might provide chaining to make it more concise. In
> | > addition there is no forwarding problems and you might have
> | > these functions anyway.
> |
> | What do you mean by "you might have these functions anyway?"
>
> I would expect a window class to have a set_height() function no
> matter what.

Okay. Maybe we should not have picked an example that constructed an
object.

> | >
> | > 2. what happens, then, if I don't have an object, but a free-standing
> | > function?
> |
> | That's the main use-case of our library!
>
> yet you show the construction of an object of type window.

You only have to read past the introduction to see that the library
applies to regular functions!

> | > a) wrap the function in an object
> | > b) do as in http://www.boost.org/libs/graph/doc/bgl_named_params.html
> | > c) provide overloads of functions that pack related parameters
> | > together or
> | > simply add defaults
> |
> | It looks like you didn't really read through the library docs. You
> | just use the library in the normal way.
>
> I know, but I'm discussing alternatives...something I think the
> authors of the library should do before submitting.

Oh, please. Do you really think I haven't spent years thinking about
and discussing alternative approaches for named parameters?

> | > about functions when they start having more than 3-4 arguments;
> | > there is almost always some abstraction lurking just waiting to be
> | > done.
> |
> | Maybe so, but there are plenty of other good arguments for named
> | parameters.
>
> What are they?

I already gave them in several ways: they make code more readable and
to allow you to take advantage of default arguments without regard to
parameter order.

-- 
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

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