
Joe Gottman wrote:
"Joel de Guzman" <joel@boost-consulting.com> wrote in message news:diphko$tba$1@sea.gmane.org...
David Abrahams wrote:
Joel de Guzman <joel@boost-consulting.com> writes:
Rebinding semantics are there _precisely_ and _only_ to solve a problem posed by nullability.
Sorry, I don't buy that.
Why not?
I think this is again an artifact of the confusion between the dual interfaces that optional provides. optional has an identity crisis of being a pointer (as the author's original model) and a variant<T, nil> (which I suggested later on). The rebinding behavior that Fernando rationalized was long and winding and confusing. I don't recall anymore his exact rationale. All I know is that when you have to explain your design using so much wordings, then something is wrong, and I don't buy the gobbledegook.
Here is an interesting thought experiment. What should std::swap do with optional<X &>? In general, swap(x, y) usually has the same effect as the following code, except for perhaps a stronger exception guarantee and faster performance: Foo temp(x); // Step 1. Assume x and y are of type Foo x = y; // Step 2 y = temp; // Step 3
That being the case, what would the following code do? int a = 1; int b = 2; optional<int &> x(a); optional<int &> y(b); swap(x, y);
Assume that swap is not specialized for optional, and consider two cases. Case 1: rebind. Step 1 of swap above binds temp to a, step 2 rebinds x to b and step 3 rebinds y to a. Thus the end result is that x and y are each rebound to what the other one was pointing to before.
Case 2: no rebind. In this case, Step 1 above binds temp to a as before. But step 2 results in *x = *y, so a is set equal to b and both a and b now equal 2. Then step 3 results in *y = *temp, so b is set equal to a, but since a and b are already equal due to step 1, there results in no change. Thus the end result is that the original value in a is lost.
Of course we would specialize swap for optional<T> to call swap(*x, *y) if both x and y are initialized, but I think the fact that this is not equivalent to the unspecialized version is an argument in favor of the rebind semantics.
Interesting point! Now consider this: int a = 1; int b = 2; tuple<int&> x(a); tuple<int&> y(b); swap(x, y); What happens after the swap? The same thing happens! before swap a: 1 b: 2 x: 1 y: 2 swap a: 2 b: 2 x: 2 y: 2 Yet, does tuple have to change and assume a rebinding behavior as optional did? Definitely not! (Aside: Keep in mind that we never touched on the nullability of optionals. There's no nulled optional at all anywhere in this thought experiment). At most, I might be inclined to think that boost::reference_wrapper does the right swap and rebind behavior (**): int a = 1; int b = 2; reference_wrapper<int> x(a); reference_wrapper<int> y(b); before swap a: 1 b: 2 x: 1 y: 2 swap a: 1 b: 2 x: 2 y: 1 (**) reference_wrapper rebinds only on explicit copy construction and assignment from another reference_wrapper. Never from assignment from a T (its embedded type). Cheers, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net