That's completely insane. If there's always a value in your optional it has no reason to be an optional, if there may not be a value in your optional you must check for it.
That's completely insane. If there's always a value in your optional it has no reason to be an optional, if there may not be a value in your optional you must check for it.
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
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.
if (my_pointer != NULL)
do_stuff(*my_pointer)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.
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.
"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.
For instance, the ++ operator doesn't work for std::optional. For a native pointer, you just have to know (how?) not to use it.
> 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.
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 speedSo 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.
C++'s optionals are less "safer pointers" and more "stack-allocated pointers" (nor to be confused with pointers to stack allocations).
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.
do_stuff(my_optional.value())
Is also safe, it throws if the value is absent, the safety check is performed behind the scenes.But people might not want to throw an exception, so
if (my_optional)
do_stuff(*my_optional);
Must also be allowed.
The consequence is someone can also just do do_stuff(*my_optional)
No safety check is done and you get undefined behavior if the value is absent.I don't know rust so I suspect it has a language construct which c++ lacks that prevents you from doing
let Some(obj) = my_optional
do_stuff(obj);