|
Boost : |
Subject: Re: [boost] [optional] Thoughts on disallowing assignment for wrapped references.
From: Mostafa (mostafa_working_away_at_[hidden])
Date: 2011-09-08 00:15:46
On Tue, 06 Sep 2011 19:50:38 -0700, Fernando Cacciola
<fernando.cacciola_at_[hidden]> wrote:
> Hi Mostafa,
>
>>> optional<T>
>>> f()
>>> {
>>> optional<T> result;
>>> // do stuff
>>> return result;
>>> }
>>>
>>
>> However, in the latter
>> case, there is no loss of generality since the above would still be a
>> no-no
>> where T a reference type
> >...
> > Or did I miss something in your response?
>
> You totally missed his point. Please allow me to advise you on how to
> avoid that: do not to pick any spot to make a counter-argument. If you
> do, you'll miss the point, and you risk loosing our interest in
> constructively arguing with you.
>
> In fact, in this particular thread, it is you the one presenting an idea
> for us to discuss, so it is really important that you handle the
> discussion appropriately.
I think what you are pointing out are the dangers of straw man
argumentation, and I agree with you. However, not all cases of straw man
discussions are intentional. Sometimes, as in the above case, one party
in the discussion may truly misunderstand the other's message, be it the
communicatee's fault, the communicator's fault, or some combination of the
two. I try my best to understand the other party's intent (and I assume
so do others). The only remedy I see to such confusion is further
communication.
> In Robert's example, it is easy to see--or should be easy to see--that
> the fact that the optional<T> is being returned is secondary, perhaps
> even irrelevant, to the point he is making
> His point is about the shortcoming of lacking assignment, not about
> object lifetimes (and BTW, is the same point Nevin and I made earlier).
I still contend my previous assertion is true for all forms of Robert's
example, and I will try to prove it.
To recap, I claim:
1) Were the assignment operator disallowed for optional<T&> and only
optional<T&>, there would no loss of programmatic generality when
optional<T&> is used as a local variable.
2) Were the assignment operator disallowed for optional<T&> and only
optional<T&>, there would be a loss of programmatic generality when
optional<T&> is used as a member variable.
I think 2) is easy to see, so I'll go about proving 1).
Proof (or more correctly an outline of a proof):
Let D1 = { x | x is a sequence of C++ declarations in some function foo,
there exists o,
o is a local instance of optional<T&>,
o appears as an lvalue in some assignment expression in
some declaration in x }
Let D2 = { y | y is a sequence of C++ declarations in some function qux,
there exists alt_opt,
alt_opt<T> is equivalent to optional<T> in all respects
except when T is reference type,
when T is a reference type the assignment operators of
alt_opt will be disallowed }
Let F be a map, in the mathematical sense, from D1 into D2 defined for all
x in D1 by:
1) For the initial, contiguous, top-most scopeS in x where a local
instance o of optional<T&> appears as an lvalue in an assignment
expression in some non-conditonal declaration:
a) replace the last occurrence of said assignment expression in the
enclosing scope with a 1-arg alt_opt<T&> constructor in F(x).
b) all previous occurrences of said assignment expressions in the said
enclosing scope for F(x) can be refactored such that the lvalue term is of
type T&.
2) If in x there are any uses of o outside and after the said initial,
contiguous, top-most scopeS indicated in 1), then:
a) in F(x) refactor those use cases into another function, say bar2,
call bar2 at the end of the enclosing scope for all occurrences of 1-arg
alt_opt<T&> constructor declarations,
b) apply F(x) recursively to bar2
The case of where a local instance o of optional<T&> appears as an lvalue
in an assignment expression in some conditional declaration in x should
now be trivial to handle, so I'll leave it out because it just adds
verbosity to the proof.
I will now demonstrate the application of F to an expanded version of the
example that you gave in the immediately previous post. Attached are two
files, D1.txt and D2.txt. The function in D2.txt is the result of
applying F to the function in D1.txt, annotations are provided in D2.txt
pointing out how F was applied.
In fact, from the above proof, it should be easy to see that assertions 1)
and 2) hold for any type T, not just optional<T&>.
------------------
The latter explanation may seem overly pedantic, however, since the
assertion I made is directly relevant to the intent of this thread
(exploring the consequences of disallowing the assignment operators for
optional<T&>), and since you disagreed with my assertion, I saw it
necessary to provide a justification for my assertion.
------------------
Thanks for clarifying the example, now I think I have enough information
to understand what the relevant implications of disallowing assignment
operators for optional<T&> would be, namely:
1) they may make generic programming harder because the generic programmer
may have to handle the case of optional<T> and optional<T&> separately.
2) There would be some loss of generality w.r.t. to the existing behaviour
of optional<T&> if optional<T&> were used as a member variable.
3) Even though there is no loss of generality w.r.t. to the existing
behaviour of optional<T&> if optional<T&> were a local variable, the
programming paradigm it forces on users may not be convenient.
Mostafa
template <typename T>
optional<T&> foo()
{
...
optional<T> o;
if(x)
{
o = p1();
//Use o
o = p2();
//Use o
o = q1();
//Do 1
}
if(y)
{
o = q2();
//Do 2
}
if(o)
{
//Do 3
}
switch ( cond )
{
case a : o = foo1(); break ;
case b : o = foo2(); break ;
case c : o = foo3(); break ;
case d : o = foo4(); break ;
case e : o = foo5(); break ;
default : // o remains uninitialized
}
if(o)
{
//Do 4.
}
o = foo8();
//Do 5.
}
template <typename T>
alt_opt<T&> foo()
{
...
if(x)
{
/* Application of F.1.b */
T & t1 = p1();
//use t1
/* Application of F.1.b */
T & t2 = p2();
//use t2
/* Application of F.1.a */
alt_opt<T&> o(q1());
//Do 1
//Application of F.2.a */
return bar1(o, other_relevant_parameters_here);
}
if(y)
{
/* Application of F.1.a */
alt_opt<T&> o(q2());
//Do 2
//Application of F.2.a */
return bar1(o, other_relevant_parameters_here);
}
}
/* Application of F.2.b */
template <typename T>
alt_opt<T&> bar1(o, other_relevant_parameters_here)
{
//Do 3: use o here ...
switch(cond)
{
case a:
{
/* Application of F.1.a */
alt_opt<T&> o1(foo1());
//Application of F.2.a */
return bar2(o1, other_relevant_parameters_here);
}
case b:
{
/* Application of F.1.a */
alt_opt<T&> o1(foo2());
//Application of F.2.a */
return bar2(o1, other_relevant_parameters_here);
}
//likewise for c,d,e
default:
{
/* Application of F.1.a */
alt_opt<T&> o1;
//Application of F.2.a */
return bar2(o1, other_relevant_parameters_here);
}
}
}
/* Application of F.2.b */
template <typename T>
alt_opt<T&> bar2(o, other_relevant_parameters_here)
{
if(o)
{
//Do 4.
}
/* Application of F.1.a */
alt_opt<T&> o1(foo8());
//Application of F.2.a */
return bar3(o1, other_relevant_parameters_here);
}
/* Application of F.2.b */
template <typename T>
alt_opt<T&> bar3(o, other_relevant_parameters_here)
{
//Do 5.
return o1;
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk