
Sam Partington wrote:
Hi there,
Firstly whilst reviewing this thread and the optional docs I spotted a couple of minor typos :
"(Re)binds thee wrapped reference." : thee -> the "untitialized" -> uninitialized
In the In-place factory discussion, the last code segment has been corrupted slightly : template<class inplacefactory=""></class>
should presumably be :
template<class InPlaceFactory>
Ha, thanks.
Also, whilst the docs I think in general are good, I find some of the acronyms used in the docs slightly too informal for formal documentation, for instance IMO and w.r.t.. Whilst they are well known, it does cause the brain to stall momentarily whilst trying to understand some quite difficult concepts.
OK.
Now, onto the discussion at hand.
I must admit I find the whole rebinding interface very ambiguous.
Just to keep the discussion clear, is a matter of semantics not interface.
What we have is a reference that is potentially null. In my mind that is a pointer (wrapped up obviously), and not an optional at all.
Maybe you meant "not a reference at all"? Well, in optional<> this is implemented as a true reference, not as a pointer like in reference_wrapper(). So is more like that there is a reference or nothing.
I use a class called ref_ptr<> for that purpose, and it has served me well - A smart pointer with no ownership.
That this discussion is going on so long and is so disputed it seems to me that there is no right-way, and the best way of fixing it is to disallow T& altogether.
This is one choice, yes. I hope we can solve it because dorpping T& totally breaks generic programming.
But if it were to stay I would say that the rebinding is very surpising for someone used to using references.
And so is the no-rebinding alternative. Look for _my_ thought experiment in another pos. Do it yourself, show it to your mate, and share with me the results.
In the rationale the first example states "If you assign to an uninitialized optional<T&> the effect is to bind (for the first time) to the object. Clearly, there is no other choice".
[...]
Remove the operator=(const T&)
Yes, this could also work. Initially I was against such operator, but for the wrong reasons, so in the end I accepted it.
int i = 0; optional< int & > o(i); int n = 0; *o = i; // assigns new value o = optional<int&>(i); // rebinds, nice and explicitly
The problem which was raised is that it adds an unnecesary verbosity. That is, why can't you define: o = val ; as a convenient shortcut for: o = optional<T>(val); All by itself, is looks quite reasonable. Now you brought this issue back but into the context of optional references. Is it totally clear to everyone that this rebinds? o = optional<int&>(i); Joel de Guzman said that he wouldn't be against rebinding in this case. He's against rebinding in the direct-assignment case, so simply dropping direct-assignment is definitely a way out, even at the cost of dropping some sugar. One could say: optional does not support a convenient direct assignment operator becasue it could hide the true semantics of the assignment, which are clear if only assignment from another optional is used. (Followed by an example) A related note about the use of operator * You said that, even for optional<T&>, it is clear that this: *o = i; is UB if 'o' is uninitialized. And so there is no problem defining that assignment as really just the assignment of the underlying type, which in the case of optional<T&> doesn't rebind. Now I wonder, if instead of operator*, we used value() (or whatever), would it be just as clear? Consider: int a = 1 ; int b = 2 ; int c = 3 ; int& ra = a ; int& rb = b ; int& rc = c ; optional<int&> o(ra) ; // binds to a // Nullable interface *o = rb ; // assing 'b' to 'a' o = none ; // releases 'a' *o = rc ; // !!! UB !!! Cleary IMO // Container interface o.value() = rb ; // assing 'b' to 'a' o.reset() ; // releases 'a' o.value() = rc ; // !!! Still UB !!! ¿But cleary enough? -- Fernando Cacciola SciSoft http://fcacciola.50webs.com/