[parameter] Lack of safety?

There are cases where boost::parameter can translate its arguments to the wrong arguments at the function implementation side. I'm hoping that I'm doing something wrong, but it seems like a problem with the parameter library. The parameter library suggests creating global variables named with the names of the arguments to your function. If you have an inner scope at the calling site with a variable with the same name, things don't work. I'm okay if this simply results in a compiler error, but in some fairly simple cases, it can correctly compile to the wrong call to the implemented function. Here's an example: void FooImpl( int x, int y ) { // Gets x = 8, y = 14. We wanted x = 12, y = 8. } BOOST_PARAMETER_KEYWORD( tags, x ) BOOST_PARAMETER_KEYWORD( tags, y ) typedef boost::parameter::parameters< tags::x, tags::y > FooParams; template< typename ArgumentPack > void FooImpl( ArgumentPack const& args ) { typename boost::parameter::binding< ArgumentPack, tags::x, int >::type xx = args[ x | 12 ]; typename boost::parameter::binding< ArgumentPack, tags::y, int >::type yy = args[ y | 14 ]; FooImpl( xx, yy ); } // Some overloads are left out. This shouldn't matter. template< typename T0 > void Foo( T0 const& a0 ) { FooImpl( FooParams()( a0 ) ); } void Bar( int y ) { ... Foo( y = 8 ); ... } Notice that Bar has an argument with the same name as one of the global variables declared with BOOST_PARAMETER_KEYWORD. I can't think of a general solution to this problem. It might be better to use the call syntax "Foo( y( 8 ) );" instead because overloaded function call operators are less common than assignment operators. This does not remove the danger, however; it only disguises it better. Another solution might be to put all of the global variables in their own named namespace so that one has to qualify their use. E.g.: "Foo( arg::y = 8 );". Some other naming convention might also mitigate the problem. Note that my example looks fairly artificial because I've simplified it so much, but it's not as unlikely as it looks. The global variable is called something that meaningfully describes the argument. It is not so unlikely for a caller to have a variable with the same purpose in the context of the call, and it is not unlikely for that to have the same name. Hopefully I'm missing something important here. Please correct my misunderstanding if that's true. -Fred Bertsch

"Fred Bertsch" <fred.bertsch@gmail.com> writes:
There are cases where boost::parameter can translate its arguments to the wrong arguments at the function implementation side. I'm hoping that I'm doing something wrong, but it seems like a problem with the parameter library.
I guess it depends on your point of view, but I don't think this can reasonably be viewed as a library problem
The parameter library suggests creating global variables named with the names of the arguments to your function.
Well, namespace-scope constants, yeah.
If you have an inner scope at the calling site with a variable with the same name, things don't work.
It seems natural to me that if you have something declared at an inner scope with the same name and you use that name without qualification, the compiler picks up the inner declaration (except in the case of ADL, which is an abomination ;->). That's just the normal C++.
I'm okay if this simply results in a compiler error, but in some fairly simple cases, it can correctly compile to the wrong call to the implemented function.
Here's an example:
void FooImpl( int x, int y ) { // Gets x = 8, y = 14. We wanted x = 12, y = 8. }
BOOST_PARAMETER_KEYWORD( tags, x ) BOOST_PARAMETER_KEYWORD( tags, y )
void Bar( int y ) { ... Foo( y = 8 ); ^^^^^ The problem happens right here, before the parameter library can
<schnipp most of the Boost.Parameter related stuff because it's not relevant to the problem> possibly get a chance to intervene and do something wrong (or right). I realize why, in a language with built-in support for named parameters, you might expect this to work, but we can't work magic here --- we can only get pretty close :^). In C++, what would you expect the expression y = 8 to do in the context of this function body? If you want to reference the keyword object, you either need to avoid hiding it (pick a different name for your function parameter), or use qualification to reference the other symbol. In this case, since your keyword objects are in the global namespace, it would be ::y = 8 HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com

I can see that there's no way to make the assignment operator do any better. I didn't mean to imply otherwise. However, that doesn't change the fact that it doesn't do the right thing. I would claim that if code far from a call can change the order of parameters in a function call, and if the compiler won't tell me about it, then this is dangerous. I don't mean to say that it could be done better. It's really a very slick library. I'm just saying that I won't recommend its use to my coworkers. I think it would be reasonably safe, however, if you put the argument identifiers in a separate namespace. I like that idea. It's potentially ugly, but it should be considerably safer. -Fred Bertsch On 4/12/06, David Abrahams <dave@boost-consulting.com> wrote:
"Fred Bertsch" <fred.bertsch@gmail.com> writes:
There are cases where boost::parameter can translate its arguments to the wrong arguments at the function implementation side. I'm hoping that I'm doing something wrong, but it seems like a problem with the parameter library.
I guess it depends on your point of view, but I don't think this can reasonably be viewed as a library problem
The parameter library suggests creating global variables named with the names of the arguments to your function.
Well, namespace-scope constants, yeah.
If you have an inner scope at the calling site with a variable with the same name, things don't work.
It seems natural to me that if you have something declared at an inner scope with the same name and you use that name without qualification, the compiler picks up the inner declaration (except in the case of ADL, which is an abomination ;->). That's just the normal C++.
I'm okay if this simply results in a compiler error, but in some fairly simple cases, it can correctly compile to the wrong call to the implemented function.
Here's an example:
void FooImpl( int x, int y ) { // Gets x = 8, y = 14. We wanted x = 12, y = 8. }
BOOST_PARAMETER_KEYWORD( tags, x ) BOOST_PARAMETER_KEYWORD( tags, y )
<schnipp most of the Boost.Parameter related stuff because it's not relevant to the problem>
void Bar( int y ) { ... Foo( y = 8 ); ^^^^^ The problem happens right here, before the parameter library can possibly get a chance to intervene and do something wrong (or right).
I realize why, in a language with built-in support for named parameters, you might expect this to work, but we can't work magic here --- we can only get pretty close :^). In C++, what would you expect the expression
y = 8
to do in the context of this function body? If you want to reference the keyword object, you either need to avoid hiding it (pick a different name for your function parameter), or use qualification to reference the other symbol. In this case, since your keyword objects are in the global namespace, it would be
::y = 8
HTH,
-- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- F

"Fred Bertsch" <fred.bertsch@gmail.com> writes:
I can see that there's no way to make the assignment operator do any better. I didn't mean to imply otherwise. However, that doesn't change the fact that it doesn't do the right thing.
I would claim that if code far from a call can change the order of parameters in a function call, and if the compiler won't tell me about it, then this is dangerous.
How different is that from this situation? int x; void f(int x) // "code far from a call" { // ... lots of code a_call(x); // I thought I was passing ::x } Here code far from a call can affect the meaning of that call. I don't see why the order of parameters is especially more sacrosanct than other changes to the meaning of a function call.
I don't mean to say that it could be done better. It's really a very slick library. I'm just saying that I won't recommend its use to my coworkers.
That's your perogative of course. Maybe you should tell them to avoid using scopes, though, because lexical scoping can cause the same problems without this library being involved ;-)
I think it would be reasonably safe, however, if you put the argument identifiers in a separate namespace. I like that idea. It's potentially ugly, but it should be considerably safer.
Normally the keyword objects should be declared in a nested namespace of the one that declares functions whose parameters they identify, and that should generally be a different namespace from that of the functions that use those keyword objects. However, it's idiomatic to bring those keywords in via using directives to make them available without qualification. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Fred Bertsch" <fred.bertsch@gmail.com> writes:
I think it would be reasonably safe, however, if you put the argument identifiers in a separate namespace. I like that idea. It's potentially ugly, but it should be considerably safer.
Normally the keyword objects should be declared in a nested namespace of the one that declares functions whose parameters they identify, and that should generally be a different namespace from that of the functions that use those keyword objects. However, it's idiomatic to bring those keywords in via using directives to make them available without qualification.
Hi, I got used to using key objects and have grown to like them a lot (not only for boost.parameter, see phoenix local variables for example http://tinyurl.com/3mn6w). I typically place such key objects in a particular namespace and bring them in through the using directives. True, the keys that are hoisted through the using directive tend to clash with function arguments (and member variables) since they are typically named similarly (e.g. length, size, width). Sure, you can qualify them to avoid ambiguity (e.g. tags::length, tags::size), but it's not as pretty. Recently, I've been toying with the idea of using a different naming convention for keyword objects to alleviate the situation. Here's an example where I use capitalized CamelCase for keyword objects: foo((Length=10, Width=200)) Just a thought... Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
participants (3)
-
David Abrahams
-
Fred Bertsch
-
Joel de Guzman