this post was submitted on 11 Nov 2023
19 points (88.0% liked)

C++

1773 readers
5 users here now

The center for all discussion and news regarding C++.

Rules

founded 1 year ago
MODERATORS
top 13 comments
sorted by: hot top controversial new old
[–] Fal@yiffit.net 9 points 1 year ago (2 children)

I fully support Result types, but you're probably better off using rust at that point

[–] porgamrer@programming.dev 6 points 1 year ago

I get your point, but in this case it's not that we are pining for our favourite features from other languages, it's that even C++20 doesn't support any sensible style of error handling.

It just says "here are exceptions but also don't actually use them lol".

I'm paid to work on a vast C++ codebase which I am free to modernise but not to port. But when it comes to error handling there's not really anything to modernise to, so it's just this hige maintenance burden I can't fix.

[–] BatmanAoD@programming.dev 5 points 1 year ago

...arguably you're better off using Rust anyway, if you have a choice.

[–] namingthingsiseasy@programming.dev 7 points 1 year ago (2 children)

Overall, I agree. Exceptions are messy and make it difficult to reason about code. That said, I think the macro at the bottom is even worse. I think a better solution to the one posted in the article is to use std::expected instead. This gives you a typed union that allows you to return either a successful result or an error type.

What's nice about it is that you don't need to add endless amounts of if success {...} else {...} blocks. You can use the monadic operations (and_then, transform, etc.) to add your logic as normal while letting the compiler smoothly take care of doing the error checks. (In fact, I really wish golang has something similar to this, it would get rid of the endless error checking you have to write manually.)

I wasn't able to find an example using std::expected, and I tried writing one myself, but my version of g++ doesn't seem to support it yet. But here is a nice std::optional example that should be pretty close to what you would do with std::expected.

[–] mercator_rejection@programming.dev 2 points 1 year ago* (last edited 1 year ago) (1 children)

The main problem with std:: expected is lack of language support. In theory, it works well as an alternative to exceptions, with nice self contained monadic statements. In practice, it is actually much worse than what the article suggests.

main issues -

  1. as I said, no language level support. You eventually end up with messy code somewhere because the library code can't simplify things enough. You end up with if checks strew about that really oaught to be a language paradigm.

  2. there is not a lot of code making use of it, so at the boundaries of your code you have to make adaptations to and from std:: expected from whatever some library chose to use.

  3. adapting your existing codebase is basically impossible. Perhaps if you are starting a new project you can do it, but it is different enough that all your existing code must be updated to accommodate the new paradigm and it's just an awful experience doing the work and being in a mix of error handling.

[–] cschreib@programming.dev 1 points 1 year ago

I guess you mean std::expected, not std::exception?

[–] BatmanAoD@programming.dev 1 points 1 year ago (1 children)

A construct that's not supported by g++ is not a superior alternative to a simple macro.

That said, once support is near-universal, it probably will be preferable.

Yeah, I meant to include that in my post but forgot. I actually started out thinking that it wouldn't be too hard to implement on top of std::optional but then went down a rabbit hole to see if it already existing in the standard library.

In any case, you could also always use abseil for features that haven't landed in the compiler yet. At work, I'm stuck on c++14, but having a great time using plenty of features from later versions thanks to abseil.

[–] aport@programming.dev 4 points 1 year ago (1 children)

Me, still using negative int values to represent errors in 2023 😴

[–] lysdexic@programming.dev 6 points 1 year ago

Me, still using negative int values to represent errors in 2023 😴

The C++ committee really dropped the ball by adding std::optional in C++17 but failing to follow suit and add a std::result monadic vocabulary type similar to Rust's std::result. Supporting a vocabulary type that provides syntactic sugar to handle both success and error return types represents a missed opportunity to improve C++'s readability and developer experience.

[–] porgamrer@programming.dev 3 points 1 year ago* (last edited 1 year ago) (1 children)

I tried coming up with a decent Result type and Try macro in C++ and got nowhere. To be usable I need something like this:

auto varname = Try(expression);

Where the Try expression will either return the error type immediately or evaluate to the success type.

As far as I can tell there's no portable way to implement that macro in C++20, and nothing coming down the pipe either. I don't think chaining lambdas is good enough. It can make the code uglier than just manually checking returns.

I'll be happy if anyone can correct me though. The best I managed was still pretty gross:

TryBind(varname, expression);

Works, but it just looks like a bad DSL at that point.

[–] QuadriLiteral@programming.dev 2 points 1 year ago (1 children)

BOOST_OUTCOME_TRYX may be what you're looking for. It's only available on gcc and clang though.

[–] porgamrer@programming.dev 3 points 1 year ago

Yeah, I came across that. I presume it just uses the GCC statement expressions extension under the hood.

No can do though, it has to work with MSVC too.