6 ms·
Google has been doing a very similar, but definitely somewhat uglier, thing with StatusOr<...> and Status (as seen in absl and protobuf) for quite some time. A
by jchw 1y ago
Google has been doing a very similar, but definitely somewhat uglier, thing with StatusOr<...> and Status (as seen in absl and protobuf) for quite some time.
A long time ago, there was talk about a similar concept for C++ based on exception objects in a more "standard" way that could feasibly be added to the standard library, the expected<T> class. And... in C++23, std::expected does exist[1], and you don't need to use exception objects or anything awkward like that, it can work with arbitrary error types just like Result. Unfortunately, it's so horrifically late to the party that I'm not sure if C++23 will make it to critical adoption quickly enough for any major C++ library to actually adopt it, unless C++ has another massive resurgence like it did after C++11. That said, if you're writing C++ code and you want a "standard" mechanism like the Result type, it's probably the closest thing there will ever be.
[1]: https://en.cppreference.com/w/cpp/utility/expected https://en.cppreference.com/w/cpp/utility/expected
- a_t48 1y agoThere’s a few backports around, not quite the same as having first class support, though.
- jchw 1y agoI believe the latest versions of GCC, Clang, MSVC and XCode/AppleClang all support std::expected, in C++23 mode.
- loeg 1y agoFacebook's Folly has a similar type: folly::Expected (dating to 2016).
- throwaway2037 1y agoIf I had to guess, that idea came from Andrei Alexandrescu.
- loeg 1y agoBingo. https://github.com/facebook/folly/commit/4d932ecc53c7a72267179e58eeed7ec56eb7dc53 https://github.com/facebook/folly/commit/4d932ecc53c7a722671...
- CJefferson 1y agoI had a look. In classic C++ style, if you use *x to get the ‘expected’ value, when it’s an error object (you forgot to check first and return the error), it’s undefined behaviour! Messing up error handling isn’t hard to do, so putting undefined behaviour here feels very dangerous to me, but it is the C++ way.
- jchw 1y agoThe reason it works this way is there's legitimately no easy way around it. You're not guaranteed a reasonable zero value for any type, so you can't do the slightly better Go thing (defined behavior but still wrong... Not great.) and you certainly can't do the Rust thing, because... There's no pattern matching. You can't conditionally enter a branch based on the presence of a value. There really is no reasonable workaround here, the language needs to be amended to make this safe and ergonomic. They tried to be cheeky with some of the other APIs, like std::variant, but really the best you can do is chuck the conditional branch into a lambda (or other function-based implementation of visitors) and the ergonomics of that are pretty unimpressive. Edit: but maybe fortune will change in the future, for anyone who still cares: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2688r3.html https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p26...
- CJefferson 1y agoYou could assert. You could throw. I can’t understand how, this modern age where so many programs end up getting hacked, that introducing more UB seems like a good idea. This is one odd the major reasons I switched to rust, just to escape spending my whole life worrying about bugs caused by UB.
- jchw 1y agoAssertions are debug-only. Exceptions are usually not guaranteed to be available and much of the standard library doesn't require them. You could std::abort, and that's about it. I think the issue is that this just isn't particularly good either. If you do that, then you can't catch it like an exception, but you also can't statically verify that it won't happen. C++ needs less of both undefined behavior and runtime errors. It needs more compile-time errors. It needs pattern matching.