|
Boost : |
From: Fernando Cacciola (fcacciola_at_[hidden])
Date: 2003-08-30 16:55:02
Hi Mat,
Thanks for the input.
optional<> is now out on the field and it is the only utility of its kind I've ever seen in C++, at least in real use. This has
the drawback that there is very little experience with it. Therefore, in a way it is a sort of experiment, even though it is
now a fixed part of Boost.
optional<> will evolve, that's for sure, as user's experience show which design desicions were right and which were wrong.
I might even deprecate it and submit a replacement if it becomes clear that a drastic change is neccesary.
Right now I still believe that the pointer-like interface is correct, because I add it specifically to solve a real problem and
it did solve it.
My first optional (named differently then) had the problem that it was really difficult to track which variables were
'optionals' and hence it was easy to forget to make the neccesary steps to mantain integrity (not to use an uninitialized
optional). At some point I realized that I needed something at the syntax level that help me keep in mind that those variables
are possibly uninitialized, and so I moved from value() member functions to operatos * and ->
The pointer-like interface is just about syntax really.
Instead of opt.value() you type (*opt) or opt->
This alone shouldn't be a problem.
What I think it is a problem are other design descicions that I made in order to make other parts of the interface with the
pointer-like interface. Namely, the lack of implicit construction and direct assignment.
These two points are raised here by Mat and have been raised by many others in the past.
My main argument is that if those were allowed, you could write:
optional<int> opt ;
opt = 1 ;
int i = *opt ;
and the assymetry didn't look right to me.
Now I understand that generic uses of optional<> beg for conventional 'syntax' for assignment and initialization.
I could drop the pointer-like interface but only if replaced by some member function that aids to the fact that the value being
accessed may be undefined, that is, I know from previous experience that the following code better be invalid:
opt = 1 ; // OK, never undefined
int i = opt ; // WARNING, possibly undefined
opt.foo(); // WARNING, possiby undefined
The current alternative is:
opt.reset( 1 ) ;
int i =*opt;
opt->foo();
And another alternative could be:
opt.value() = 3 ;
int i = opt.value();
opt.value().foo();
I once had a version that recongized the fact that assigment and initialization was never underfined, and that only access was
problematic, so I could write:
opt = 3 ;
int i = opt.value();
this seemed right at first, but I made a mistake that now I recongnize was about the _implementation_ of the idea rather than of
the idea itself.
I implemeted it by declaring operator T&() and not operator T const&().
That was silly as I found myself writting: opt.foo() and having the same problems I intended to solve by adding the accesor
'value()'.
Today, on the face of all the versions I've tried and the user report I have now about the uses you want but are unsupported, I
will carefully think about adding direct initialization and implict construction yet retaining the pointer like interface which
is intended to be a familiar 'syntax' for _accessing_ the optional in those contexts were uninitialized optionals have undefined
behavior.
That is, optional would have the straight interface of a value wrapper, with conventional value semantics and syntax, in all
parts of the interface were behaviour is well defined even in presence of uninitialized optionals. This includes direct
assignment and implicit construction.
But for accessing the value, which is the only operation that has undefined behaviour if it is uninitialized, you need to do it
through operators * and ->
Well, this is a good time for all of you to speak. The heat is on again.
Fernando Cacciola
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk