12 ms·
Modern C++ Features – std::optional
- NegativeLatency 8y agoCan’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)
- awestroke 8y agoSounds like a useless feature in that case
- snowAbstraction 8y agoIn case, what do you say about returning a class instance from a function in Java? Joking aside, the feature gives you both a value type and documents the intent of function intentionally possibly not returning a value.
- dasloop 8y agoThis will be C++ std::expected: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0323r3.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p032... Returns a value (as in std::optional) than can be null. If so you will get an error explaining what happened.
- archgoon 8y agoJava has Optional<T> which is actually nullable, unlike the C++ std::optional (which is a value type, not a pointer). So even if it were nullable, it seems that people find value in expressing "This may not return a valid object, you need to check" as an actual object type is useful. https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html https://docs.oracle.com/javase/8/docs/api/java/util/Optional...
- pjmlp 8y agoThey plan to sort out that problem when value types are finally part of the JVM.
- jcrites 8y agoI wish and hope that, in some future version of the Java language, they will change the behavior of Java references so that they are explicitly non-null by default, and require an annotation or signifier of some kind to mark them as nullable. The Kotlin language (JVM-based) got this right: https://kotlinlang.org/docs/reference/null-safety.html https://kotlinlang.org/docs/reference/null-safety.html In the meantime, Java coding best practices dictate treating all references as non-null in first-party code (defensively checking references received from third-party code, such as with Objects.requireNonNull), and avoiding nullable references in favor of Optional.
- staticassertion 8y agoThis won't happen. But Java is likely to get value types, which would be non-null just as in other languages with value types. The issue of Optional<T> being nullable is an extremely uncommon one - I have seen it happen once ever, and there were way bigger issues going on that happened to manifest that way. It's one of those "that's dumb but ultimately makes no difference" problems that many languages have.
- jcelerier 8y agouh ? unlike languages such as java, or c#, objects aren't nullable in C++, only pointers to objects. You can't do for instance struct foo { // whatever }; foo my_function() { return nullptr; } and thus, std::optional<int> my_function() { return nullptr; } does not compile (rightly).
- iBelieve 8y agoWouldn't it be more correct to say that Java and C# don't have nullable objects either, it's just that they're always used via pointers, so any object reference can be nullable, unlike C++, which allows objects to be passed by value and thus not be nullable?
- pjmlp 8y agoC# is not like Java. struct Vector { int x, y; } public class Program { public static void Main() { Vector v = null; } } Also does not compile: "Cannot convert null to 'Vector' because it is a non-nullable value type"
- jcelerier 8y agowell, change that struct into class and it does AFAIK :p Basically, just given `public foo myFunction() { ... }` there's no easy way to know
- winstonewert 8y agoNope. class and struct are almost the same thing in C++ .
- jcelerier 8y agoyes, I was talking about C#.
- 8y ago
- HippoBaro 8y agostd::optional is designed for value semantic. It wouldn't make sense to use it to return a pointer-type.
- Koshkin 8y agoBut in C and C++ a pointer is a value.
- beached_whale 8y agoNo, 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
- pjmlp 8y agoC# has value types, you can't set structs to null.
- beached_whale 8y agoTrue. Most things are reference types though
- pjmlp 8y agoNo in the case of Nullable, which behaves just like std::optional.
- beached_whale 8y agoI see what you are saying, yes. Also, in c++ if you try to use an empty value in an optional<T> it isn't using undefined behavior as dereferencing a null pointer would, plus with optional you get value semantics so things like copy are deep vs copying the pointer. Not sure about C# nullables, but I guess if you copy the .value member it is deep.
- slavik81 8y agoNo. 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.
- repsilat 8y agoTo expand on this: In C++ a useful heuristic could be to think of values like Java primitives. A C++ integer takes up some amount of space. Maybe it's four bytes on your platform. Integers on your platform take up four bytes. Not "four bytes plus a pointer", but four bytes and that's it. In those four bytes you can store 2^32 values. There's nowhere else to store whether the integer is null -- if you wanted to signal to someone that the value was "missing", you would either have to, - Come up with your own "in-band" signal, like "-(2^31) means 'missing'", or - Have an out-of-band signal, like a separate boolean variable, or keep a pointer to "integer or null". (Pointers being nullable is arguably kinda weird still.) Functions that return an integer in C++ on your platform will put four bytes "in the right place" on the stack. (Or in a register? I don't really know what calling conventions look like...) Again, there's nowhere to signal that the value is missing -- if you don't fill in that memory location or that register, well, there will just be some other (undefined) value sitting in its place that the caller will read. Ditto functions that expect integer arguments etc. Now, this has some interesting consequences: for stack-allocated values in C++, "object identity" tends to be preserved less often than in Java. When you put an object into a `vector`, you'll probably put a copy there. When you mutate that copy or call some function on it, you're not mutating the original. You can get back to "Java semantics" of object identity and nullability etc by using pointers and explicit heap storage.
- cesarb 8y ago> Functions that return an integer in C++ on your platform will put four bytes "in the right place" on the stack. (Or in a register? I don't really know what calling conventions look like...) On a register. I don't know of any mainstream platforms which return simple values like an integer through the stack. For larger values (larger than a word or a couple of words), on the other hand, usually the calling function passes the called function a pointer to a location on the stack where it should write the result. Either way, like you said "there's nowhere to signal that the value is missing".
- Buge 8y agoNo 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> .
- boltzmannbrain 8y agoBeen using boost for this (what else is new?): https://theboostcpplibraries.com/boost.optional https://theboostcpplibraries.com/boost.optional https://stackoverflow.com/questions/22227839/how-to-use-boostoptional https://stackoverflow.com/questions/22227839/how-to-use-boos...
- beached_whale 8y agoconstexpr 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.
- jstimpfle 8y ago> 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.
- marcosdumay 8y ago> 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.
- mianos 8y agoThis is not really true of any mature system. There are many reasons to design a schema in normal form, including performance, maintainability and space optimisation. Database design outside start-ups is a fairly mature area and normal form is well proven good practice.
- marcosdumay 8y agoI will call bullshit on that. I have never seen a database on the 6th normal form on the real world, and I don't believe any exist outside of a lab. Anything beyond 3rd normal form brings very sporadic gains to maintainability and space optimization. The usual case is that you lose those. About performance, I can imagine there exist situations where you'll gain some by going further than the 3rd normal form, but I don't believe anybody sees that as a normal situation.
- th0br0 8y agoThe 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-stdoptional-in-c https://stackoverflow.com/questions/44217316/how-do-i-use-st... My recommendation would be to just use https://github.com/martinmoene/optional-lite https://github.com/martinmoene/optional-lite for cross-platform stuff.
- spullara 8y agoIt looks like this is just temporary until the feature is no longer experimental so they can modify the standard library.
- klodolph 8y ago"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 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.
- th0br0 8y agoGCC moved it to <optional> with the release of GCC7. Note that we're now at GCC8, clang 4 added it - I believe we're now at clang 6. Therefore, it's by far no longer something that's experimental IMHO. (standardised in C++17 after all)
- 0xmaverick 8y agoI 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.
- klodolph 8y agoYou may find std::variant also very useful. You can do something like std::variant<Error, Foo>.
- cpeterso 8y agoA 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! http://en.cppreference.com/w/cpp/utility/optional http://en.cppreference.com/w/cpp/utility/optional
- nneonneo 8y agoIs 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.
- Retra 8y agoI suppose the difference would be that pointers-to-bool don't make a ton of sense in the first place, but using optional to wrap a boolean is a very reasonable thing to to.
- Matheus28 8y agoI don’t see it being reasonable at all. If you need more than two values, use an enum?
- deleted 8y ago[deleted]
- cpeterso 8y agoThat's a good point. If need a bool variable, there is a decent chance you will need more values later. In that case, an enum is more extensible and the names are more descriptive. Like the classic "Daily WTF?": enum Bool { True, False, FileNotFound }; http://thedailywtf.com/articles/What_Is_Truth_0x3f_ http://thedailywtf.com/articles/What_Is_Truth_0x3f_
- adamnemecek 8y agoI wonder if at some point there will be cpp that's kinda like kotlin to java. Source code compatible but a clean cut.
- Animats 8y agoThe 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.
- klodolph 8y agoEdit: Rewritten. 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++.
- Stratoscope 8y agoLet's keep things civil please. Saying "I can only imagine that you're trying to start a fight" is rarely helpful.
- klodolph 8y agoOkay, rewritten. I honestly thought the parent comment was baiting, since complaining about C++ safety is... well, rarely helpful and usually just starts arguments.
- Stratoscope 8y agoThank you for the rewrite, much appreciated. If I may offer a tip, when someone takes a position that seems unreasonable or baiting or argument-prone, I try to apply the principle of charity: I assume that their intentions are good. Of course I don't always succeed at this! ;-)
- sharpercoder 8y agoOptional 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.
- anaphylactic 8y agoI 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.
- Koshkin 8y agoTo be fair, not all languages make this easy.
- geezerjay 8y agoI 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.
- TheAnig 8y agoWith all the modern features being used, I wonder how one would go about learning modern C++.
- anaphylactic 8y agoThat'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?
- Koshkin 8y agoIf you know the basics, cppreference.com is your best bet.
- stochastic_monk 8y agoAnd reading real code. It’s important to see how these pieces all go together. Just reading cppreference is like familiarizing yourself with legos without seeing how to build something with them.
- jzl 8y agoThere are several good books about c++11 and c++14, though I'm not sure about 17. "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996 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-Programmers-Depth/dp/0134383583 https://www.amazon.com/Discovering-Modern-Scientists-Program...