Hacker News new | ask | show | jobs
by adastra22 1064 days ago
This is essentially "Rust's error handling in C++", no? I generally think this is an improvement and good to have, but I'm wondering if there are any hidden differences.

The C++ standard library already exposes a std::optional type. Does this stx::Option type differ from that one?

2 comments

> The C++ standard library already exposes a std::optional type. Does this stx::Option type differ from that one?

std::optional is a stack pointer, like other C++ pointers you can straight up deref’ it and get an UB.

It looks like stx::Option is an actually option type, it focuses on safety and will throw if “unsafe” methods are called on the wrong state. It also provides a slew of monadic operators to operate over values.

std::optional is not a pointer. And it has a safe dereference method called value() if you want the extra runtime check which operator* skips.
C++ got this wrong, again. The default usage should be safe, with an escape hatch, i.e. deref operator should be safe and value() should be unsafe.

Ideally, a sufficiently smart compiler would be able to see code like

    if (auto t = get_optional())
    {
        do_something(*t);
    }
And elide the double safety check, but because optional is a library feature not a language feature, the compiler needs to detect general usages of that pattern rather than specifically optimising for a language level construct. That's another place c++ is going in the wrong direction in...
The default option is high performance and less verbose.
The default option is dangerous and vulnerable being incorrect unless you explicitly use it in a different way. This is a symptom of it being a library and not a language feature.

As another example, imagine if span was a language feature. A compiler could bounds check at compile time, and fully elide the checks at runtime in many scenarios (like in a loop over the span).

A pointer with an opt-in, less convenient, safe dereference... is still a pointer. You could add a `value` observer to unique_ptr or shared_ptr.

The entire point of optional is that you can swap it in for a raw or unique pointer and it'll be cheaper because no allocation. That's not the use case for an option type.

It's not a pointer. `std::optional<T>` is a class that directly contains a `T` (within a union) and happens to offer `operator*` and `operator->` providing an API similar to a smart pointer. This does not make it a pointer (there's nothing else it could be pointing to).

Also, in an ideal world, stdlib implementations would support error-checking for `std::optional::operator*`. "Undefined behavior" just means the standard doesn't specify what should happen. Both "let's use it for unsafe optimizations" and "trigger assertion failures" are valid implementions of undefined behavior, and a good implemention should allow the user to make this choice. For gcc, see -D_GLIBCXX_ASSERTIONS. Though I'll say that it's unfortunate that C++ implementations tend to default to "unsafe optimizations" and that the opt-in to safety is not standardized.

> and will throw if “unsafe” methods are called on the wrong state

I haven’t looked at the code but the stx documentation said it doesn’t use exceptions.

The doc states it panics, maybe that's process termination, but either way it doesn't let you do the thing.
operator*() is UB on a missing optional, but ::value() exists if you want safety built into the call.
C++ also has `std::expected<T,E>`.
Thanks, TIL.