Originally posted as TotW #163 on July 11, 2019
Are nulls really a billion-dollar mistake?
Let’s say you need to implement a function with a parameter that may or may not
exist. You might be tempted to use modern, fancy-schmancy
this. However, if the object is big enough that it should be passed by
absl::optional is probably not what you want. Consider the
following two declarations:
void MyFunc(const absl::optional<Foo>& foo); // Copies by value void MyFunc(absl::optional<const Foo&> foo); // Doesn't compile
The first option probably doesn’t do what you want. If someone passes a
Foo will be copied by value into the
absl::optional<Foo>, which will then be passed by reference into the function.
If your goal was to avoid copying the
Foo, you haven’t.
The second option would be great, but unfortunately is not supported by
If you need a parameter that might not exist, pass it by
const * and let
nullptr indicate “does not exist.”
void MyFunc(const Foo* foo);
This will be just as efficient as passing by
const Foo&, but supports null
The documentation for
std::optional points out that you can use a
std::reference_wrapper to work around the fact that optional references aren’t
void MyFunc(absl::optional<std::reference_wrapper<const Foo>> foo);
However, this has quite a lot of boilerplate, and is difficult to read. Therefore, we don’t recommend it.
absl::optional can be used if you own the thing that’s optional. For
example, class members and function return values often work well with
absl::optional. If you don’t own the thing that’s optional, just use a
pointer, as described above.
If your object is small enough to not need pass-by-reference, you may take the
object wrapped in an
absl::optional by value. For example:
void MyFunc(absl::optional<int> bar);
If you expect all callers of your function to already have an object inside of
absl::optional, then you may take a
const absl::optional&. However, this
is rare; it usually only occurs if your function is private within your own