once again: boost.bind namespace conflicts and how to solve them

I wonder if it makes sense to write an additional header for boost.bind (and maybe boost.function) that provides the library interfaces meeting the 'modern' boost requirements, i.e.: a) this header should be placed in the bind subdirectory, e.g. boost/bind/bind.hpp b) this header should introduce a separate namespace 'bind' or 'function' to avoid the well-known namespace clashes with boost::lambda that are _really_ annoying. c) this header should not declare the placeholders in an anomymous namespace. (I don't know what was the intention behind that but it makes it impossible to write 'using boost::_1') Comments? Stefan

Stefan Slapeta wrote:
I'm really not sure what do you mean by "modern" boost requirements.
a) this header should be placed in the bind subdirectory, e.g. boost/bind/bind.hpp
What purpose does that serve? Why not boost/bind/bind/bind.hpp?
Again, what purpose would that serve? The only name that bind.hpp "reserves" in boost is 'bind'. Defining a namespace 'bind' still reserves the same name in boost, namely, 'bind', except that user code is now uglier.
The original intent has been to make the placeholders globally available. As identifiers that start with an underscore are not allowed at the global namespace, and since defining a variable in a header would cause link errors, the placeholders have been put in an unnamed namespace.

Peter Dimov wrote:
I'm really not sure what do you mean by "modern" boost requirements.
None of the libraries that have recently been included into boost placed their headers in the boost root directory. I don't know whether this has become a (formal) requirement but that's what I wanted to express.
It was just an idea how to separate this header from the existing. One of many possible.
Try to include boost/bind.hpp and boost/lambda/bind.hpp at the same time (just for matters of uniformity: this is the first time where I don't agree that one of those includes is in a subdirectory and the other is not!) I've not found any solution for how to use e.g. _1 from boost.lambda in one function and _1 from boost.bind in another _without_ having to qualify these two everytime, which is totally ugly IMO.
ah ... I understand. IIRC, the _1 from boost.lamba are types and don't have these problems therefore. This means more or less that I'll never be able to write 'using boost::_1', no? Stefan

Stefan Slapeta wrote:
Currently boost/ appears to contain 98 header files. Bringing this down to 97 wouldn't be much of an improvement.
You bring up the legitimate problem of bind's _1 clashing with lambda's _1 (when "using namespace boost::lambda" is in effect), but I totally don't see what this has to do with moving boost::bind to boost::bind::bind. To answer your specific question, ::_1 selects the Bind placeholder and boost::lambda::_1 selects Lambda's one; consequently, "using ::_1" is an using declaration for Bind's _1, and "using boost::lambda::_1" is the using declaration for its Lambda counterpart. I only tested them on VC 7.1, though; maybe your compiler doesn't accept them?
No, Lambda's placeholders are variables in an unnamed namespace, too. MPL's placeholders are types. :-)
This means more or less that I'll never be able to write 'using boost::_1', no?
Probably not. You'll use "using namespace boost::placeholders" instead, when bind is modified to conform a bit more closely to TR1. The problem is that this breaks existing code. Of course when you have two using directives, one for Bind and one for Lambda, _1 will once again become ambiguous.

Peter Dimov wrote:
Currently boost/ appears to contain 98 header files. Bringing this down to 97 wouldn't be much of an improvement.
I didn't propose to delete the old one.
Symmetry: boost::lambda::bind, boost::bind::bind (or maybe boost::function::bind and also include boost.function library there)
This might be a different discussion but I simply don't understand what are the rules for putting boost.bind and boost.function in the 'global' boost namespace and many other libraries not. Historical reasons? A matter of interface size? [...]
There will be other headers for the TR1 implementations, so breaking existing code is not so much my problem. Stefan

Peter, I've been expecting for some time that you were going to put the placeholders in a sub-namespace of boost, if only to avoid the ODR violations it is currently causing. No? The fact that I have to write mpl::_1 just to avoid colliding with <unnamed>::_1 is disconcerting at best. If another library came along and did what boost/bind/placeholders.hpp does, it would cause a clash. My suggestion, assuming you care about backwards compatibility, is: boost/bind/placeholders.hpp declares placeholders in namespace boost::bind::placeholders. boost/bind/bind.hpp has the current contents of boost/bind.hpp, except that placeholders are not declared in the <unnamed>:: boost/bind.hpp #include <boost/bind/bind.hpp> #include <boost/bind/placeholders.hpp> namespace { using namespace boost::bind::placeholders; } Is something wrong with that? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Nevertheless, please think about putting bind itself (and maybe the rest) into namespace boost::bind as well, if only to introduce some kind of symmetry between bind and lambda!
_PLEASE_ can we have this? Stefan

David Abrahams wrote:
Correct me if I'm wrong, but the ODR violations are caused by the use of an unnamed namespace; this is not related to whether the placeholders are in a subnamespace of boost. It seems to me that Lambda's placeholders should be susceptible to the same sort of ODR violations. (I know that I asked you for an ODR/_1 example once and you provided it, but I don't remember what it was and can't find it at the moment. Sorry.)
First mover advantage, you know. (Kidding.)
But does not _define_ them? (I had boost::placeholders in mind for a namespace, consistent with std::tr1::placeholders; when you use 'boost' as a substitute for 'std::tr1', boost::bind::placeholders won't work.)
Hm. What is the difference between this directive and the simple using namespace boost::bind::placeholders; ? I can't think of any. This, of course, will still require you to use mpl::_1. I assume that you intend to fix all your includes to belong to... err, point to the using-directive-less version?

Peter Dimov wrote:
It won't prevent me from having to use qualification or local "using." It will help because I won't be forcing the ambiguity problem on the user just by dint of #including a boost header. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Peter Dimov wrote:
True.
this is not related to whether the placeholders are in a subnamespace of boost.
True again. That's a separate issue; anything we put outside boost is subject to unresolvable conflicts. <unnamed>:: is especially vulnerable.
It seems to me that Lambda's placeholders should be susceptible to the same sort of ODR violations.
I don't know what lambda does. I know mpl doesn't do that.
(I know that I asked you for an ODR/_1 example once and you provided it, but I don't remember what it was and can't find it at the moment. Sorry.)
int x(int); template <class T> void f() { boost::bind(x, _1); } Now all you need is for two translation units to instantiate f<X> for some X, the same in each TU.
You could define them as constants. Maybe enums would work: enum _1t { _1 }; enum _2t { _2 }; ??
Okay, as long as you cooperate with phoenix and lambda, as far as I'm concerned.
Honestly, I'm not sure there is any.
This, of course, will still require you to use mpl::_1.
Yes, I expect that. Anyone conscientious will have to use qualification or local using directives to access placeholders.
You bet. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Peter Dimov wrote:
Ideally? You all use the same placeholders. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

Howard Hinnant wrote:
I've also wondered if a general "placeholder library" is possible.
Thanks Howard! I didn't dare to ask myself. However, I'm wondering if the placeholders as specified in TR1 can be used by mpl?!?! Stefan

Howard Hinnant wrote:
It's possible to write libraries so that they recognize the same placeholders, but the existing Bind and Lambda codebases aren't written in such a way. However I'd expect Metrowerks's implementation to be able to use Bind's and Lambda's placeholders; the only thing that is needed is appropriate specializations of std::tr1::is_placeholder. By specializing std::tr1::is_bind_expression for boost::_bi::bind_t<R, F, L>, std::tr1::bind should even be able to recognize a nested boost::bind subexpression. Daniel Wallin's suggestion of using #define _1 arg<1>() which is both a type and a value can enable even type (mpl) and value (bind, lambda) placeholders to be unified. Of course I can only imagine what the response to a macro _1 would be from an audience that can't even stand a global _1.

David Abrahams wrote:
Ideally, yes. In practice, this can't happen, not with the current implementations of Bind and Lambda. I don't know about Phoenix, but it doesn't use _1 anyway. The problem on Boost.Bind's side is that it recognizes placeholders by their exact type, rather than using an is_placeholder metafunction, as specified in TR1. So it can only work with its own placeholders. The problem on Lambda's side is that Lambda's placeholders aren't really placeholders, but full-featured Lambda functors. Lambda doesn't use an is_placeholder metafunction either. In principle, Bind can use Lambda functors as placeholders, but getting around the ODR problem would require Borland's version of placeholders (inline functions named _k) to be used on all compilers in Bind, and such an inline function can't be a Lambda functor. In addition, Bind's placeholders are assignable. This allows Bind's function objects to be assignable as well. In Lambda, _1 = _1 is not an assignment, but a lambda expression. The framework outlined in TR1 - is_placeholder and is_bind_expression - allows two implementations of tr1::bind to recognize each other's placeholders and subexpressions, so that you can mix and match lib1::bind, lib2::bind, lib1::_1 and lib2::_2 in the same bind expression. Unfortunately, neither Boost.Bind nor Boost.Lambda honor this framework, and there are objective reasons for both to not change to accommodate it. (In Bind's case, support for older compilers.)

Peter Dimov wrote:
Well, lambda is going to be undergoing an integration with Phoenix, which leaves ample room for flexibility on that end. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (5)
-
David Abrahams
-
Howard Hinnant
-
Peter Dimov
-
Stefan Slapeta
-
Stefan Slapeta