Boost.Bimap - first/second and left/right

Hi all, I think we must discuss this issue together so we can settled it down. Lets analyze the rationale step by step. (1) Interface for the bidirectional mapping. That interface have to be compatible with existing code that work with standard maps. The best way IMHO to achieve this is that you can view the container from the two sides and see something compatible with std::map<X,Y> for the left one and with std::map<Y,X> for the right one. (2) This force us to use first/second notation for the left view (first is the left element and second the right one) and for the right view (where the names are inverted, first is the right element and second is the left one) If you have code like: template< class Pair > class PrintPair { void operator()( const Pair& p ) { std::cout << p.first << "-->" << p.second << std::endl; } } template< class Map > void print( const Map & m ) { std::for_each( m.begin(), m.end(), PrintPair< Map::value_type >() ); } typedef bimap<int,std::string> bm_type; bm_type bm; bm.insert( bm_type::value_type(1,"one") ); bm.insert( bm_type::value_type(2,"two") ); It will work with both sides views print( bm.left ); // 1 --> one // 2 --> two print( bm.right ); // one --> 1 // two --> 2 (3) (from other thread) For bm (the above view) we have some options: a) bm can be left without any special function and so force the user to write .left or .right to refer to it. b) bm can be the same as bm.left. This IMHO introduce an asymmetry to the interface. The left view became the more important than the right view. c) bm can be used for something new. Give the user a new view of the mapping: a set of relations. This design is symmetric. It forces the user to write .left to refer to the std::map<X,Y> view but this is a good thing, because is documented in the code what view is being used. This option is more elegant and powerful that the other ones. Because it is a new view we can use the symmetric left/right notation for it members so the design is complete. If we use first and second, the above view could be confused with the left view. Jeff has proposed to go with (a) In the current framework this is achieve using: typedef bimap<A,B,unconstrained_set_of_relation> bm_type; The library use (c) because it is very useful to be able to insert the elements or ask for the size, etc directly. And because it allows us to extend the framework by selecting different set of relations. So first/second are used in the side views and left/right in the above view. What do you think about this? Regards Matias

Matias Capeletto wrote:
(3) (from other thread) For bm (the above view) we have some options:
a) bm can be left without any special function and so force the user to write .left or .right to refer to it. b) bm can be the same as bm.left. This IMHO introduce an asymmetry to the interface. The left view became the more important than the right view.
Don't like this much.
c) bm can be used for something new. Give the user a new view of the mapping: a set of relations. This design is symmetric. It forces the user to write .left to refer to the std::map<X,Y> view but this is a good thing, because is documented in the code what view is being used. This option is more elegant and powerful that the other ones. Because it is a new view we can use the symmetric left/right notation for it members so the design is complete. If we use first and second, the above view could be confused with the left view.
Nod, we definitely want the set of relations view I think, the question is whether this is the view offered by the bimap, or whether you access it via a member, so we have: bimap.left - left map view bimap.right - right map view bimap.relation - relation set view. But otherwise no special members in bimap itself. In fact the more I think about this the more I like it, but I'd like to here what others think. John.

John Maddock wrote:
Matias Capeletto wrote:
Nod, we definitely want the set of relations view I think, the question is whether this is the view offered by the bimap, or whether you access it via a member, so we have:
bimap.left - left map view bimap.right - right map view bimap.relation - relation set view.
But otherwise no special members in bimap itself. In fact the more I think about this the more I like it, but I'd like to here what others think.
I like that you have to say bimap.relation -Thorsten

On 2/27/07, Thorsten Ottosen <thorsten.ottosen@dezide.com> wrote:
John Maddock wrote:
Matias Capeletto wrote:
Nod, we definitely want the set of relations view I think, the question is whether this is the view offered by the bimap, or whether you access it via a member, so we have:
bimap.left - left map view bimap.right - right map view bimap.relation - relation set view.
But otherwise no special members in bimap itself. In fact the more I think about this the more I like it, but I'd like to here what others think.
I like that you have to say
bimap.relation
What are the reasons for this change? (If it is changed I think we should call it bimap.above) I like the above view because the set of relations is handy (and better suited) for general not directed task such as insertion (it is more efficient in it than in the side views), iteration, questions as size or empty. Why not to make it easily accessible? If you want to know the size and there is not such thing as the relation view, what side would you choose? bimap.left.size()? What is special about it? bimap.size() is IMO a better way to express in the code your intention. Regards Matias

Matias Capeletto wrote:
What are the reasons for this change? (If it is changed I think we should call it bimap.above)
I like the above view because the set of relations is handy (and better suited) for general not directed task such as insertion (it is more efficient in it than in the side views), iteration, questions as size or empty. Why not to make it easily accessible?
If you want to know the size and there is not such thing as the relation view, what side would you choose? bimap.left.size()? What is special about it? bimap.size() is IMO a better way to express in the code your intention.
First off I confess that I'm not completely set on this change - just that it's one possible solution to a recurring theme among reviewers. The rationale is that it forces you to specify *which* view you're talking about. Maybe an alternative would perhaps be to document bimap from the start as a "container of relations that also offers left/right associative views". BTW "above" is a terrible name: call a relation a relation IMO :-) John.

On 2/28/07, John Maddock <john@johnmaddock.co.uk> wrote:
Matias Capeletto wrote:
What are the reasons for this change? (If it is changed I think we should call it bimap.above)
I like the above view because the set of relations is handy (and better suited) for general not directed task such as insertion (it is more efficient in it than in the side views), iteration, questions as size or empty. Why not to make it easily accessible?
If you want to know the size and there is not such thing as the relation view, what side would you choose? bimap.left.size()? What is special about it? bimap.size() is IMO a better way to express in the code your intention.
First off I confess that I'm not completely set on this change - just that it's one possible solution to a recurring theme among reviewers. The rationale is that it forces you to specify *which* view you're talking about. Maybe an alternative would perhaps be to document bimap from the start as a "container of relations that also offers left/right associative views".
It can be an option. But there are some issues with the actual default set type of relations for this view. It is left_based. This introduced an asymmetry and is not a very good idea to present this view as the principal one. Being left based means that it uses the left side view to build the set type of relation. The elements are stored in the same way that in the left map. The left element is the only one used internally as a key for indexing ( relation(1,0.1) and relation(1,0.2) are equal to the compare functor. ) This save us a B.MI index and is mandatory for performance reasons. The only way to make this view symmetric is to use unconstrained_set_of_relation as the default, but we will get back to the first scenario where we the only way to work with the mapping is through the side views. IMO if the docs clearly show the asymmetry of the left_based default it is better to choose it over unconstrained_set_of_relation. This is why I think it is better to present the bimap as the composition of two complementary signature-compatible std::maps. And later introduce the set view of relations as another way to see the mapping. We have to see if it is good to talk about this issues in the one minute tutorial.
BTW "above" is a terrible name: call a relation a relation IMO :-)
I was looking for something that follow the .left and .right notation. The "above" view is a synonym of the set of relations in the docs. Regards Matias

Matias Capeletto wrote:
Hi all,
I think we must discuss this issue together so we can settled it down.
Lets analyze the rationale step by step.
(1) Interface for the bidirectional mapping. That interface have to be compatible with existing code that work with standard maps. The best way IMHO to achieve this is that you can view the container from the two sides and see something compatible with std::map<X,Y> for the left one and with std::map<Y,X> for the right one.
(2) This force us to use first/second notation for the left view (first is the left element and second the right one) and for the right view (where the names are inverted, first is the right element and second is the left one)
I found the phrase "first/second notation" a bit confusing. Mainly becasuse is easy to mixup the notation for each view with the notation for each element in the view's value_type. You can refer to is as: "a std::pair-compatible struct is used as the value type of the left/right views".
(3) (from other thread) For bm (the above view)
As I said in another post, considering the set of relation objects as a view "from above" is a valid but nevertheless arbitrary POV. You can of course choose to see it like that, but make sure not to present it as a natural choice. Ultimately, you don't actually need to think of it as being above, or over, or along, or whatever...
a) bm can be left without any special function and so force the user to write .left or .right to refer to it. b) bm can be the same as bm.left. This IMHO introduce an asymmetry to the interface. The left view became the more important than the right view. c) bm can be used for something new. Give the user a new view of the mapping: a set of relations.
Right, and as others said I'd call it ".relations". Definitely not ".above".
The library use (c) because it is very useful to be able to insert the elements or ask for the size, etc directly. And because it allows us to extend the framework by selecting different set of relations.
So first/second are used in the side views
More precisely, to name the elements of the value_type of the side views.
and left/right in the above view.
Again, more precisely, to name the elements of the value_type of the above view. Being more precise is important in your context because you not only have left/right elements but also left/right views. Sometimes the right overload is a bit hard to pick up. Best -- ------ Fernando Cacciola SciSoft http://certuscode.wordpress.com http://fcacciola.50webs.com http://fcacciola.wordpress.com
participants (4)
-
Fernando Cacciola
-
John Maddock
-
Matias Capeletto
-
Thorsten Ottosen