
On Wed, 31 Aug 2011 09:41:58 -0700, Fernando Cacciola <fernando.cacciola@gmail.com> wrote:
Hi Mostafa,
Let me start by warning that this discussion is likely to wind up in an endless argument, and I might not have the time to follow up. In any case, if you google for it you should be able to find the really long discussions that led to the current choice.
Just to clarify, I'm not arguing for or from a certain position, rather, I'm looking for enlightenment as to what the consequences of disallowing the assignment operator for optional<T&> are. I would be greatly disappointed if you did not follow up to any of my direct queries to you, even if it is just a pointer to look elsewhere.
From the 3 possible choices, each one favors certain aspects at a certain expense, so no choice is a sensible winner, yet one has to be made, and so I did.
A lot of people is concerned with the current semantics. And a lot of people was concerned with the old semantics (it used to assign the referee). In fact, the main reason (if not the only one) why Boost.Optional did not make it into Cpp0x is precisely the concerns about choice of assignment semantics for references.
The problem with disabling assignment all toghether is basically the same as assigning the referee instead of the wrapper: it breaks consistency.
In a highly generic context, which is so typical in modern C++, the T in optional<T> might very well be itself a reference type, so any special behavior might result in an practical shotcomming, even possibly a show stopper: it could simply rule out optional<> as an element of a generic library.
To be a little more precise:
A library that uses optional<T> such that the choice of T is entirely external to the library *requires* that optional<> is completely consistent regardless of T. If it where to behave specially in the case T is a reference type (or for that matter, a non-POD type, a compound type, or whatever) then the library itself would have to explicitely handle all such differences. Recall that in a generic context, the typename T could very well be a reference type even without the &, so any time you consider what optional<T&> should do, substitute that for optional<U> and think again.
The current choice is to favor consistency for the sake of generic libraries, where the library itself would not discriminate whether T happens to be a reference type or not.
Ok, I think I understand your argument. To clarify, by consistency here you mean consistency of programming in a generic environment, so that, as you say, a generic library would not have to discriminate between T and T&. Disclaimer1: What I will say below may have already been discussed, if so, please feel free to tell me to google it. Disclaimer2: I have very little experience with writing generic libraries in the C++ sense. Disclaimer3: Besides the documentation, I have no experience in actually using optional. What are the consequences of doing away with the assignment operator totally, and just having a no-parameter reset method that resets optional<...> state to uninitialized? In my naive point-of-view, the majority of Boost.Optional use case would involve member-variable types, or interface level types, ie, parameter types and return types. Racking my brain, I can't think of a draw back with respect to this use case if the above thought experiment were carried out.
Keep in mind that
*Assignment to optional<T> is simply not the same as assignment to a T*.
It cannot possibly be for the simple fact that you cannot assign to nothing. Hence, optional<> itself must define *its own* assignment semantics, so the argument that it should follow the assignment semantics of the underlying T is not that strong because it clearly cannot do that on all cases (when the lvalue is empty). It is a sensible argument of course, but it must be weighted against the equally sensible counter argument that it breaks consistency.
To clarify, in explaining my motivation for the intent of this thread I was saying that a casual programmer would expect that the assignment semantics of T would be a subset of the assignment semantics of optional<T>, not the other way around. In general, for any wrapper type class "wrap" and wrapped type T, I think that a casual programmer would expect the semantics of the "natural operations" of T to be a subset of the semantics of the those same operations wherever defined on wrap. The reasoning being that the casual user of wrap who is accustomed to the conventions of T will not be unduly surprised when he/she applies those same conventions to wrap. And in this sense, there is no inconsistency between T and wrap, since the "natural operations" of T just seem to work with wrap, whenever wrap truly represents its underlying type. But, this is tangential to the intent of this thread.
P.S.: Please do not just counter argument my counter arguments without having first googled, read and processed this very same discussion in the past.
Fair, I understand not wanting to sound like a broken tape recorder. IMHO, this indicates a need to add a general "Design Rationale" section to the documentation, maybe incorporating summaries of the discussions that you allude to. Thanks for your enlightening response, Mostafa