|
Boost : |
Subject: Re: [boost] [optional] Thoughts on disallowing assignment for wrapped references.
From: Mostafa (mostafa_working_away_at_[hidden])
Date: 2011-08-31 05:56:40
On Wed, 31 Aug 2011 01:07:36 -0700, Jeffrey Lee Hellrung, Jr.
<jeffrey.hellrung_at_[hidden]> wrote:
> On Tue, Aug 30, 2011 at 10:23 PM, Mostafa
> <mostafa_working_away_at_[hidden]>wrote:
>
>> Boost.Optional seems to really have a lot of potential for what I want
>> to
>> do, but one thing about it has been nagging me, specifically it's
>> assignment
>> semantics for wrapped references being different from the semantics of
>> bare
>> C++ references (see http://tinyurl.com/4yna643).
>>
>
> So...you don't agree with the rationale?
>
I don't believe I wrote anything to imply that. I had a hard time
following the rationale, so I've taken the author(s) at their word.
>
>> Has/have the author(s) of the library or anyone considered disallowing
>> assignment for Boost.Optional types that wrap references, and if so,
>> what
>> would the consequences of this entail? I rather disallow assignment in
>> this
>> case, then have what's basically a wrapper class behave partially
>> differently than the type it's supposed to emulate.
>>
>
> Given that there's an entire section of the documentation devoted to the
> semantics of assignment, I'd infer the author(s) consider the various
> possibilities for assignment, including disallowing it.
They may have considered disallowing it, but there's no mention of that
consideration in the document, nor, assuming that they did consider such a
possibility, why they rejected it.
> If you disallowed
> assignment for optional<T&>, then surely you would likewise need to
> disallow
> default constructability, and then how would an optional<T&> really be
> any
> different from a T& other than the syntactic clutter?
Sorry, I don't follow you here. A defaulty constructed "optional<T&> pp;"
would convey that someone has decided not to set the value of pp, exactly
because the type of pp is *optional*<T&>. Hence, optional<T&> conveys
more information than T&.
> Perhaps you can elaborate on why the current assignment semantics are
> troubling to you...?
Let me reword and expand my concerns. I view boost::optional as a thin
wrapper for it's underlying type, with the added sugar that it can convey
whether its instance has or has not been set by the user. Hence, it
behaves very much like a smart pointer. I expect pointer semantics to be
a subset of smart pointer semantics, ie, whatever operations I can perform
on pointers, I too can perform on smart pointers (where they are allowed)
and get the same results. So for example, *p and p-> will give the same
results regardless of whether p is a plain old pointer or a smart
pointer. Where p is a smart pointer and "p + 5" is disallowed then I just
say bummer, and do "p.get() + 5"; however, where "p + 5" was allowed and
it behaved differently than "p.get() + 5", then I would be unpleasantly
shocked, no matter how in-your-face it may have been blared in the
documentation. In large software projects, heck, even in medium-sized
teams, not everyone will read the *whole* documentation, they'll just
glance enough at it to figure out how to solve their immediate need. With
respect to the documentation for Boost.Optional, yes, there is a whole
section on option<T&> assignment, but it in no way stands out from the
rest of the documentation, and even within the said section, the only clue
as to why it's there in the first place is a bold "rebind" which
automatically catches my eye, but no red flags, no caution sign, nothing
else. But my beef isn't with the documentation, as I said, even if it was
blaring with a flashing red sign, I still would be hesitant because *not
everyone reads the whole documentation*, for good or bad. Hence my desire
to disallow inconsistent behaviour with regards to existing convention.
More specifically, and to answer your question, what bugs me is that the
semantics of the operations that I can perform on T& are not a subset of
the semantics of the same operations that I can perform on optional<T&>,
per the documentation: "Now, if you assign to an initialized optional<T&>,
the effect is to rebind to the new object instead of assigning the
referee. This is unlike bare C++ references."
The rationale for such a rebinding of optional<T&> maybe very sound, and
rebinding maybe the only choice to achieve consistent behaviour with
respect to Boost.Optional, but it doesn't negate the fact that the
semantics of the assignment operation that I perform on T& are not a
subset of the semantics of the same operation that I perform on
optional<T&>. And given the near universal rule that not all programmers
read the whole documentation, there will inevitably come along some
programmer who will assume that optional<T&> behaves at least like T&
wherever the operations are defined on both (and rightly so in my
opinion), and in the course of doing some maintenance on some large code
base, the said programmer will introduce a bug that maybe easy to detect
but will be hard to diagnose because of the need to reread the
documentation. Hence my desire to explore the consequences of disallowing
the assignment operation for optional<T&> and the reason for starting this
thread.
Hopefully this explains things better,
Mostafa
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk