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 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.
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.
C++'s optionals are less "safer pointers" and more "stack-allocated pointers" (nor to be confused with pointers to stack allocations).
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);> 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 (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)For instance, the ++ operator doesn't work for std::optional. For a native pointer, you just have to know (how?) not to use it.
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.