The worst part about this is that Apple has decided to once again violate the standard.
They purposefully eliminated the `value()` accessor due to ABI issues as far as I understand from the stack overflow comments: https://stackoverflow.com/questions/44217316/how-do-i-use-st...
"Violate the standard" might be a bit harsh. The fact that you are using <experimental/optional> instead of <optional> as your header should indicate that something else is going on.
Practically speaking, it takes a while for features implemented upstream to make it into your OS of choice. If these are really critical features, you can get third-party implementations of <optional> or you can compile your own toolchain, neither of these are particularly difficult options. It can be a bit frustrating, yes, when language feature arrives on a different schedule in the library and compiler (which happens).
Mind you, #include <optional> doesn't work on my Linux box either, with GCC. And if you look at the GCC web page, https://gcc.gnu.org/projects/cxx-status.html#cxx17, it says that GCC's support for C++17 is "experimental". I know that GCC != Clang, but let's give them some time to test things before a million projects get the code compiled in and we're stuck with the implementation.
A possible std::optional footgun is that an optional object can implicitly be converted to bool, returning optional has_value(). For optional objects that may hold value types that themselves can be used in a boolean context (like bool or a pointer value), then a programmer may confuse the implicit has_value() check with returning the real value().
std::optional<bool> opt(false);
assert(opt); // true even though *opt is false!
Is this really different than a pointer (or smart pointer) pointing to a false-y object? An optional isn’t implicitly convertible to its contained type - you have to use * or .value(), so it seems like there wouldn’t be much confusion.
An optional containing a pointer seems pretty dubious. You would usually either just use a pointer and have null mean empty or use an optional containing the pointed-to type.
An optional pointer is a weird tri state thing where you can have empty or a null pointer or a non-null pointer.
The pointer dereferencing operators and -> are implemented, but without the std::bad_optional_access – accessing an empty std::optional this way is undefined behavior.*
Oh, please. Raise an exception or panic. But "undefined behavior" on dereferencing this new form of "null"? That's no good.
You say, "Oh, please." But this feature is consistent with the design mandate of the C++ language... the very foundation of its design is that you don't pay for safety if you don't want to. So I am not sure what you are trying to say.
Honestly... why aren't you just using a different language? Practically every other language invented in the past 30 years has the safety features it sounds like you want. So, why come into a discussion about some new C++ feature and complain about the fact that a safety feature is optional? This is the way it always has been for C++. This is the way pointer dereferencing works for all the new smart pointers. Dereferencing std::shared_ptr and std::unique_ptr... both unsafe, equally unsafe as std::optional. This is the way std::vector works. They're all unsafe unless you specifically use certain safer accessors like .at(). The fact that dereferencing a std::optional is unsafe is consistent with decades of changes to C++.
The standard way of dereferencing std::optional is with .value() and that does provide a check and an exception. Using * and -> is equivalent to invoking "unsafe" in other languages. You get the semantics you ask for. If you don't want unsafe behaviour it's really as simple as using the safe operator. I don't honestly see what the problem is here.
As much as I dislike most of "modern C++", the one thing they have consistently kept intact is that all the safety guarantees, at least insofar as they have performance implications, are optional. That's how it should be, by design.
There are plenty of languages that make implicit, opaque tradeoffs in order to give you some measure of protection from programmer errors. C++ was never meant to be among them.
If you want exceptions, use 'value()'. If you want minimum runtime checks you use operator*/->. This is perfectly consistent with the spirit of C++ to give you maximum control over your code.
constexpr I think is the big difference. Also the name of the empty class to reset the value to none, boost is boost::none whereas the std has std::nullopt_t. I prefer the boost name of none as nullopt sounds and looks too much like null.
That's a good point, and it's not just a problem with C++. As any project matures, the voices of current users drown out the voices of new users, and as a result discoverability gets thrown out the window. How would you engineer a project so as to avoid this fate?
Can’t you still return null from a function? So even if your return type was optional, you’d have to check if it was null in some cases before unwrapping it.
(Edit: Limited c++ experience, thanks for explaining)
No. In Java every object variable is a reference type. They're all implicitly pointers. Hence why all objects can be null. Java just hides all the dereferencing away. "Object myobject;" creates a pointer/reference rather than an actual object.
In C++ you can have pointers to objects, but they're explicitly denoted by an asterisk. The C++ equivalent would be "Object* myobject;"
However, you can also directly have object variables in C++. That's not something that exists in Java. A variable declared like, "Object myobject;" can never be null. The myobject variable is a value, just like i in "int i = 5;" is a value.
No, this isn't java/c#. In C++ only a pointer can be set to nullptr or NULL. std::optional is a value that can store a type T(T is a place holder for a type name). If T is a pointer (such as T * or int *...) then yes you could return null. But that is rare and looks weird.
So the value of an optional is either a valid value or it has no value. The default constructed std::optional<T> has no value
No you can't. "null" isn't a specific thing in c++. There's nullptr, NULL, and 0. NULL is just a fancy name for 0.
If for example you have a function with a return type of string, it must return a string. It cannot return nullptr, NULL, or 0. It could return an empty string. But in some cases you might want to distinguish between empty string and no result, in that case you would want to the return type to be std::optional<std::string> .
I find this useful for older paradigms where you want an error as well as pass in something to fill in as the output. Instead of doing bool foo(OutFoo* out_foo) or overloading Id getId(); // returns -1 if not present. You could use base::Optional<OutFoo> / base::Optional<Id> in each case respectively.
Optional is a typical feature that should be baked into the syntax. If used properly, it will be used throughout codebases, and when it is used, it adds simple, replaceable syntax.
I disagree. If a perfectly good optional type can be implemented without making new syntax, why bother making new syntax? It obscures what's going on under the hood, makes implementation needlessly complex, and increases mental overhead for users.
I fail to see how forcing syntax changes (thus breaking all IDEs) is preferable to simply adding a class, or how using a custom specialized keyword brings anything but problems when trying to replace a component.
> In programming, we often come across the situation that there is not always a concrete value for something
In database terms, the need for null values means that the data schema is denormalized. With a simpler approach there is seldom any need for these "not applicable" values.
And that's the problem with all languages with special support for "nullable" values: They glorify bad data structure design. I've seen codebases where 30-50% of the lines is just handling of null values that SHOULD NOT BE THERE and where nothing meaningful (or even functional) happens when the value is actually null.
Goes well together with OOP: In the name of isolation, each object is abstracted from all context necessary to construct a straightforward and correct program. The result is more and more meaningless boilerplate and burnt out developers.
Personally I'm fine with not assigning any value to "not applicable" variables. Or putting a sentinel there, like -1 or NULL. But adding a physical case (i.e. changing the type) to support "not applicable" cases is just not a good idea.
I think it's more helpful to think of C++ std::optional like Maybe in a functional language rather than as like a nullable type. Its primary use case is as a return value from functions, not as a data member. There are many functions where this can make good sense: parsing a string as a number, searching for an element in a collection, trying to load something from a file, taking a square root, etc.
> In database terms, the need for null values means that the data schema is denormalized.
And nobody ever use a fully normalized schema in practice, because it's cumbersome and gets in the way of solving the problem.
And that's for databases, that are optimized stable storage and data coherence, not for performance. A fully normalized schema is a performance disaster if applied to running applications.
[+] [-] th0br0|7 years ago|reply
My recommendation would be to just use https://github.com/martinmoene/optional-lite for cross-platform stuff.
[+] [-] klodolph|7 years ago|reply
Practically speaking, it takes a while for features implemented upstream to make it into your OS of choice. If these are really critical features, you can get third-party implementations of <optional> or you can compile your own toolchain, neither of these are particularly difficult options. It can be a bit frustrating, yes, when language feature arrives on a different schedule in the library and compiler (which happens).
Mind you, #include <optional> doesn't work on my Linux box either, with GCC. And if you look at the GCC web page, https://gcc.gnu.org/projects/cxx-status.html#cxx17, it says that GCC's support for C++17 is "experimental". I know that GCC != Clang, but let's give them some time to test things before a million projects get the code compiled in and we're stuck with the implementation.
[+] [-] spullara|7 years ago|reply
[+] [-] cpeterso|7 years ago|reply
[+] [-] nneonneo|7 years ago|reply
[+] [-] bobbyi_settv|7 years ago|reply
An optional pointer is a weird tri state thing where you can have empty or a null pointer or a non-null pointer.
[+] [-] geezerjay|7 years ago|reply
That isn't true, as std::optional are explicitly converted to bool to signal whether the object stores a value.
http://en.cppreference.com/w/cpp/utility/optional/operator_b...
[+] [-] hoppelhase|7 years ago|reply
Good luck with that.
[+] [-] unknown|7 years ago|reply
[deleted]
[+] [-] Animats|7 years ago|reply
Oh, please. Raise an exception or panic. But "undefined behavior" on dereferencing this new form of "null"? That's no good.
[+] [-] klodolph|7 years ago|reply
You say, "Oh, please." But this feature is consistent with the design mandate of the C++ language... the very foundation of its design is that you don't pay for safety if you don't want to. So I am not sure what you are trying to say.
Honestly... why aren't you just using a different language? Practically every other language invented in the past 30 years has the safety features it sounds like you want. So, why come into a discussion about some new C++ feature and complain about the fact that a safety feature is optional? This is the way it always has been for C++. This is the way pointer dereferencing works for all the new smart pointers. Dereferencing std::shared_ptr and std::unique_ptr... both unsafe, equally unsafe as std::optional. This is the way std::vector works. They're all unsafe unless you specifically use certain safer accessors like .at(). The fact that dereferencing a std::optional is unsafe is consistent with decades of changes to C++.
[+] [-] zik|7 years ago|reply
[+] [-] keldaris|7 years ago|reply
There are plenty of languages that make implicit, opaque tradeoffs in order to give you some measure of protection from programmer errors. C++ was never meant to be among them.
[+] [-] jlebar|7 years ago|reply
Like it, don't like it, that's cool. But it is consistent.
[+] [-] alexeiz|7 years ago|reply
[+] [-] boltzmannbrain|7 years ago|reply
https://theboostcpplibraries.com/boost.optional
https://stackoverflow.com/questions/22227839/how-to-use-boos...
[+] [-] beached_whale|7 years ago|reply
[+] [-] TheAnig|7 years ago|reply
[+] [-] jzl|7 years ago|reply
"Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" https://www.amazon.com/Effective-Modern-Specific-Ways-Improv...
"Discovering Modern C++: An Intensive Course for Scientists, Engineers, and Programmers (C++ In-Depth Series)" https://www.amazon.com/Discovering-Modern-Scientists-Program...
[+] [-] Koshkin|7 years ago|reply
[+] [-] anaphylactic|7 years ago|reply
[+] [-] NegativeLatency|7 years ago|reply
(Edit: Limited c++ experience, thanks for explaining)
[+] [-] slavik81|7 years ago|reply
In C++ you can have pointers to objects, but they're explicitly denoted by an asterisk. The C++ equivalent would be "Object* myobject;"
However, you can also directly have object variables in C++. That's not something that exists in Java. A variable declared like, "Object myobject;" can never be null. The myobject variable is a value, just like i in "int i = 5;" is a value.
[+] [-] beached_whale|7 years ago|reply
So the value of an optional is either a valid value or it has no value. The default constructed std::optional<T> has no value
[+] [-] jcelerier|7 years ago|reply
You can't do for instance
and thus, does not compile (rightly).[+] [-] Buge|7 years ago|reply
If for example you have a function with a return type of string, it must return a string. It cannot return nullptr, NULL, or 0. It could return an empty string. But in some cases you might want to distinguish between empty string and no result, in that case you would want to the return type to be std::optional<std::string> .
[+] [-] HippoBaro|7 years ago|reply
[+] [-] awestroke|7 years ago|reply
[+] [-] adamnemecek|7 years ago|reply
[+] [-] 0xmaverick|7 years ago|reply
[+] [-] klodolph|7 years ago|reply
[+] [-] sharpercoder|7 years ago|reply
[+] [-] anaphylactic|7 years ago|reply
[+] [-] geezerjay|7 years ago|reply
[+] [-] jstimpfle|7 years ago|reply
In database terms, the need for null values means that the data schema is denormalized. With a simpler approach there is seldom any need for these "not applicable" values.
And that's the problem with all languages with special support for "nullable" values: They glorify bad data structure design. I've seen codebases where 30-50% of the lines is just handling of null values that SHOULD NOT BE THERE and where nothing meaningful (or even functional) happens when the value is actually null.
Goes well together with OOP: In the name of isolation, each object is abstracted from all context necessary to construct a straightforward and correct program. The result is more and more meaningless boilerplate and burnt out developers.
Personally I'm fine with not assigning any value to "not applicable" variables. Or putting a sentinel there, like -1 or NULL. But adding a physical case (i.e. changing the type) to support "not applicable" cases is just not a good idea.
[+] [-] mattnewport|7 years ago|reply
[+] [-] marcosdumay|7 years ago|reply
And nobody ever use a fully normalized schema in practice, because it's cumbersome and gets in the way of solving the problem.
And that's for databases, that are optimized stable storage and data coherence, not for performance. A fully normalized schema is a performance disaster if applied to running applications.