• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1[/
2    Boost.Optional
3
4    Copyright (c) 2003-2007 Fernando Luis Cacciola Carballal
5
6    Distributed under the Boost Software License, Version 1.0.
7    (See accompanying file LICENSE_1_0.txt or copy at
8    http://www.boost.org/LICENSE_1_0.txt)
9]
10
11[section Design Overview]
12
13[section The models]
14
15In C++, we can ['declare] an object (a variable) of type `T`, and we can give this
16variable an ['initial value] (through an ['initializer]. (cf. 8.5)).
17When a declaration includes a non-empty initializer (an initial value is given),
18it is said that the object has been initialized.
19If the declaration uses an empty initializer (no initial value is given), and
20neither default nor value initialization applies, it is said that the object is
21[*uninitialized]. Its actual value exist but has an ['indeterminate initial value]
22(cf. 8.5/11).
23`optional<T>` intends to formalize the notion of initialization (or lack of it)
24allowing a program to test whether an object has been initialized and stating
25that access to the value of an uninitialized object is undefined behavior. That
26is, when a variable is declared as `optional<T>` and no initial value is given,
27the variable is ['formally] uninitialized. A formally uninitialized optional object
28has conceptually no value at all and this situation can be tested at runtime. It
29is formally ['undefined behavior] to try to access the value of an uninitialized
30optional. An uninitialized optional can be assigned a value, in which case its initialization state changes to initialized. Furthermore, given the formal
31treatment of initialization states in optional objects, it is even possible to
32reset an optional to ['uninitialized].
33
34In C++ there is no formal notion of uninitialized objects, which means that
35objects always have an initial value even if indeterminate.
36As discussed on the previous section, this has a drawback because you need
37additional information to tell if an object has been effectively initialized.
38One of the typical ways in which this has been historically dealt with is via
39a special value: `EOF`, `npos`, -1, etc... This is equivalent to adding the
40special value to the set of possible values of a given type. This super set of
41`T` plus some ['nil_t]—where `nil_t` is some stateless POD—can be modeled in modern
42languages as a [*discriminated union] of T and nil_t. Discriminated unions are
43often called ['variants]. A variant has a ['current type], which in our case is either
44`T` or `nil_t`.
45Using the __BOOST_VARIANT__ library, this model can be implemented in terms of `boost::variant<T,nil_t>`.
46There is precedent for a discriminated union as a model for an optional value:
47the __HASKELL__ [*Maybe] built-in type constructor. Thus, a discriminated union
48`T+nil_t` serves as a conceptual foundation.
49
50A `variant<T,nil_t>` follows naturally from the traditional idiom of extending
51the range of possible values adding an additional sentinel value with the
52special meaning of ['Nothing].  However, this additional ['Nothing] value is largely
53irrelevant for our purpose since our goal is to formalize the notion of
54uninitialized objects and, while a special extended value can be used to convey
55that meaning, it is not strictly necessary in order to do so.
56
57The observation made in the last paragraph about the irrelevant nature of the
58additional `nil_t` with respect to [_purpose] of `optional<T>` suggests an
59alternative model: a ['container] that either has a value of `T` or nothing.
60
61As of this writing I don't know of any precedent for a variable-size
62fixed-capacity (of 1) stack-based container model for optional values, yet I
63believe this is the consequence of the lack of practical implementations of
64such a container rather than an inherent shortcoming of the container model.
65
66In any event, both the discriminated-union or the single-element container
67models serve as a conceptual ground for a class representing optional—i.e.
68possibly uninitialized—objects.
69For instance, these models show the ['exact] semantics required for a wrapper
70of optional values:
71
72Discriminated-union:
73
74* [*deep-copy] semantics: copies of the variant implies copies of the value.
75* [*deep-relational] semantics: comparisons between variants matches both
76current types and values
77* If the variant's current type is `T`, it is modeling an ['initialized] optional.
78* If the variant's current type is not `T`, it is modeling an ['uninitialized]
79optional.
80* Testing if the variant's current type is `T` models testing if the optional
81is initialized
82* Trying to extract a `T` from a variant when its current type is not `T`, models
83the undefined behavior of trying to access the value of an uninitialized optional
84
85Single-element container:
86
87* [*deep-copy] semantics: copies of the container implies copies of the value.
88* [*deep-relational] semantics: comparisons between containers compare container
89size and if match, contained value
90* If the container is not empty (contains an object of type `T`), it is modeling
91an ['initialized] optional.
92* If the container is empty, it is modeling an ['uninitialized] optional.
93* Testing if the container is empty models testing if the optional is
94initialized
95* Trying to extract a `T` from an empty container models the undefined behavior
96of trying to access the value of an uninitialized optional
97
98[endsect]
99
100[section The semantics]
101
102Objects of type `optional<T>` are intended to be used in places where objects of
103type `T` would but which might be uninitialized. Hence, `optional<T>`'s purpose is
104to formalize the additional possibly uninitialized state.
105From the perspective of this role, `optional<T>` can have the same operational
106semantics of `T` plus the additional semantics corresponding to this special
107state.
108As such, `optional<T>` could be thought of as a ['supertype] of `T`. Of course, we
109can't do that in C++, so we need to compose the desired semantics using a
110different mechanism.
111Doing it the other way around, that is, making `optional<T>` a ['subtype] of `T`
112is not only conceptually wrong but also impractical: it is not allowed to
113derive from a non-class type, such as a built-in type.
114
115We can draw from the purpose of `optional<T>` the required basic semantics:
116
117* [*Default Construction:] To introduce a formally uninitialized wrapped
118object.
119* [*Direct Value Construction via copy:] To introduce a formally initialized
120wrapped object whose value is obtained as a copy of some object.
121* [*Deep Copy Construction:] To obtain a new yet equivalent wrapped object.
122* [*Direct Value Assignment (upon initialized):] To assign a value to the
123wrapped object.
124* [*Direct Value Assignment (upon uninitialized):] To initialize the wrapped
125object with a value obtained as a copy of some object.
126* [*Assignment (upon initialized):] To assign to the wrapped object the value
127of another wrapped object.
128* [*Assignment (upon uninitialized):] To initialize the wrapped object with
129value of another wrapped object.
130* [*Deep Relational Operations (when supported by the type T):] To compare
131wrapped object values taking into account the presence of uninitialized states.
132* [*Value access:] To unwrap the wrapped object.
133* [*Initialization state query:] To determine if the object is formally
134initialized or not.
135* [*Swap:] To exchange wrapped objects. (with whatever exception safety
136guarantees are provided by `T`'s swap).
137* [*De-initialization:] To release the wrapped object (if any) and leave the
138wrapper in the uninitialized state.
139
140Additional operations are useful, such as converting constructors and
141converting assignments, in-place construction and assignment, and safe
142value access via a pointer to the wrapped object or null.
143
144[endsect]
145
146[section The Interface]
147
148Since the purpose of optional is to allow us to use objects with a formal
149uninitialized additional state, the interface could try to follow the
150interface of the underlying `T` type as much as possible. In order to choose
151the proper degree of adoption of the native `T` interface, the following must
152be noted: Even if all the operations supported by an instance of type `T` are
153defined for the entire range of values for such a type, an `optional<T>`
154extends such a set of values with a new value for which most
155(otherwise valid) operations are not defined in terms of `T`.
156
157Furthermore, since `optional<T>` itself is merely a `T` wrapper (modeling a `T`
158supertype), any attempt to define such operations upon uninitialized optionals
159will be totally artificial w.r.t. `T`.
160
161This library chooses an interface which follows from `T`'s interface only for
162those operations which are well defined (w.r.t the type `T`) even if any of the
163operands are uninitialized. These operations include: construction,
164copy-construction, assignment, swap and relational operations.
165
166For the value access operations, which are undefined (w.r.t the type `T`) when
167the operand is uninitialized, a different interface is chosen (which will be
168explained next).
169
170Also, the presence of the possibly uninitialized state requires additional
171operations not provided by `T` itself which are supported by a special interface.
172
173[heading Lexically-hinted Value Access in the presence of possibly
174uninitialized optional objects: The operators * and ->]
175
176A relevant feature of a pointer is that it can have a [*null pointer value].
177This is a ['special] value which is used to indicate that the pointer is not
178referring to any object at all. In other words, null pointer values convey
179the notion of nonexistent objects.
180
181This meaning of the null pointer value allowed pointers to became a ['de
182facto] standard for handling optional objects because all you have to do
183to refer to a value which you don't really have is to use a null pointer
184value of the appropriate type. Pointers have been used for decades—from
185the days of C APIs to modern C++ libraries—to ['refer] to optional (that is,
186possibly nonexistent) objects; particularly as optional arguments to a
187function, but also quite often as optional data members.
188
189The possible presence of a null pointer value makes the operations that
190access the pointee's value possibly undefined, therefore, expressions which
191use dereference and access operators, such as: `( *p = 2 )` and `( p->foo() )`,
192implicitly convey the notion of optionality, and this information is tied to
193the ['syntax] of the expressions. That is, the presence of operators `*` and `->`
194tell by themselves —without any additional context— that the expression will
195be undefined unless the implied pointee actually exist.
196
197Such a ['de facto] idiom for referring to optional objects can be formalized
198in the form of a concept: the __OPTIONAL_POINTEE__ concept.
199This concept captures the syntactic usage of operators `*`, `->` and
200contextual conversion to `bool` to convey the notion of optionality.
201
202However, pointers are good to [_refer] to optional objects, but not particularly
203good to handle the optional objects in all other respects, such as initializing
204or moving/copying them. The problem resides in the shallow-copy of pointer
205semantics: if you need to effectively move or copy the object, pointers alone
206are not enough. The problem is that copies of pointers do not imply copies of
207pointees. For example, as was discussed in the motivation, pointers alone
208cannot be used to return optional objects from a function because the object
209must move outside from the function and into the caller's context.
210
211A solution to the shallow-copy problem that is often used is to resort to
212dynamic allocation and use a smart pointer to automatically handle the details
213of this. For example, if a function is to optionally return an object `X`, it can
214use `shared_ptr<X>` as the return value. However, this requires dynamic allocation
215of `X`. If `X` is a built-in or small POD, this technique is very poor in terms of
216required resources. Optional objects are essentially values so it is very
217convenient to be able to use automatic storage and deep-copy semantics to
218manipulate optional values just as we do with ordinary values. Pointers do
219not have this semantics, so are inappropriate for the initialization and
220transport of optional values, yet are quite convenient for handling the access
221to the possible undefined value because of the idiomatic aid present in the
222__OPTIONAL_POINTEE__ concept incarnated by pointers.
223
224
225[heading Optional<T> as a model of OptionalPointee]
226
227For value access operations `optional<>` uses operators `*` and `->` to
228lexically warn about the possibly uninitialized state appealing to the
229familiar pointer semantics w.r.t. to null pointers.
230
231[caution
232However, it is particularly important to note that `optional<>` objects
233are not pointers. [_`optional<>` is not, and does not model, a pointer].
234]
235
236For instance, `optional<>` does not have shallow-copy so does not alias:
237two different optionals never refer to the ['same] value unless `T` itself is
238a reference (but may have ['equivalent] values).
239The difference between an `optional<T>` and a pointer must be kept in mind,
240particularly because the semantics of relational operators are different:
241since `optional<T>` is a value-wrapper, relational operators are deep: they
242compare optional values; but relational operators for pointers are shallow:
243they do not compare pointee values.
244As a result, you might be able to replace `optional<T>` by `T*` on some
245situations but not always. Specifically, on generic code written for both,
246you cannot use relational operators directly, and must use the template
247functions __FUNCTION_EQUAL_POINTEES__ and __FUNCTION_LESS_POINTEES__ instead.
248
249[endsect]
250
251[endsect]
252