5 ms·
Sure, but that's not the issue. You should be using a std::optional like e.g. if (my_optional) do_stuff(*my_optional); Here's one (explicit)condi
by noselasd 8y ago
Sure, but that's not the issue. You should be using a std::optional like e.g.
if (my_optional)
do_stuff(*my_optional);
Here's one (explicit)conditional.
However if the dereferencing, *my_optional, should be safe, it too would need to perform a conditional check behind the scenes. But it doesn't - as C++ places that on the programmers hand to not sacrifice speed
- comex 8y agoNah. In simple cases like that, the compiler would always be able to optimize away an extra check, if such a check were present. After inlining operator bool and operator *, it would look something like if (my_optional->_has_value) if (my_optional->_has_value) do_stuff(my_optional->_value); else panic(); and the compiler knows that the second if statement will pass iff the first does. On the other hand, if the test is further away from the dereference, and perhaps the optional is accessed through a pointer and the compiler can't prove it doesn't alias something else, it might not be able to optimize away the check. However, that probably doesn't account for too high a fraction of uses.
- ayosec 8y agoHow is that different to this? if (my_pointer != NULL) do_stuff(*my_pointer)
- w0utert 8y agoIn terms of generated coded, it is exactly the same. But that's not the point of optional types. The point of optional types is to force you to write checks for undefined values, otherwise your code will not compile at all. In the old-fashioned style of your example, you might forget to check for the possibility of a null pointer/otherwise undefined value, and use it as if it were valid.
- 0xffff2 8y agoBut the whole genesis for this comment chain is that you can make exactly the same mistake with std::optional.
- w0utert 7y agoOnly if you deliberately unwrap the optional, which means you either don’t know what you are doing (in which case no programming language feature will be able to save you), or that you’ve considered your options and decided you want to enter the block knowing some variable can be undefined. IMO, that’s not the same as not having optionals at all, and writing unconditional blocks left and right that may or may not operate on undefined values. It super easy to just dereference any pointer you got back from some function call in C++, without paying attention. Optionals force you to either skip the blocks, or think about how to write them to handle undefineds. Also, it’s ‘code as documentation’ in some sense, which I’m a big proponent of.
- masklinn 7y ago> Only if you deliberately unwrap the optional "Deliberately unwrap the optional" is the exact same thing as "deliberately unwrap the pointer", you just deref' it and it's UB if the optional / pointer is empty. C++'s std::optional is not a safety feature (it's no safer than using a unique_ptr or raw pointer), it's an optimisation device: if you put a value in an std::optional you don't have to heap allocate it. > It super easy to just dereference any pointer you got back from some function call in C++, without paying attention. And optionals work the exact same way. There's no difference, they don't warn you and they don't require using a specific API like `value_unchecked()`. You just deref' the optional to get the internal value, with the same effects as doing so on any other pointer.
- humanrebar 8y agoNative pointers do a bunch of different things depending on the context. In contrast, optional has clear semantics. For instance, the ++ operator doesn't work for std::optional. For a native pointer, you just have to know (how?) not to use it.
- masklinn 8y agoHence going back to the original issue I pointed: > C++ does not really provide the facilities necessary for convenient, memory-safe and fast APIs. > You should be using a std::optional like e.g. […] if the dereferencing, *my_optional, should be safe And once again a terrible API puts the onus back on the user to act like a computer.
- simias 8y agoThis is solved in Rust by letting you test and unwrap at the same time: if let Some(obj) = my_optional { do_stuff(obj); } >However if the dereferencing, my_optional, should be safe, it too would need to perform a conditional check behind the scenes. But it doesn't - as C++ places that on the programmers hand to not sacrifice speed So basically that turns C++ optional types into fancy linter hints which won't actually improve the safety of the code much. I understand C++'s philosophy of "you pay for what you use" but that's ridiculous, if you use an optional type it means that you expect that type to be nullable. Having to pay for a check is "paying for what you use". If you don't like it then don't make the object nullable in the first place and save yourself the test. That's just optimizing the wrong part of the problem.
- masklinn 8y ago> So basically that turns C++ optional types into fancy linter hints which won't actually improve the safety of the code much. C++'s optionals are less "safer pointers" and more "stack-allocated pointers" (nor to be confused with pointers to stack allocations).
- maccard 8y agoYou can also do it in a one-liner in C++ if you're using shared pointers: if(auto obj = my_weak_ptr.lock()) { do_stuff(obj); } > Having to pay for a check is "paying for what you use". If you don't like it then don't make the object nullable in the first place and save yourself the test. The point is that I can choose _when_ to pay that cost (e.g. I can eat the nullability check at this point, but not at this point, and I can use more sophisticated tooling like a static analyser to reason that the null check is done correctly). Is it more error prone? yes. Does it allow for things to horribly wrong? yes. Is "rewriting it in rust" a solution? No. If I want to pay the cost of ref-counting, I can use shared/weak ptrs.
- aliceryhl 8y agoThe rust code in question is not using reference counting.