3 ms·
Idk, to me that constant Result<User, Error> looks extremely ugly and unergonomic, even just to type. I understand that this is complicated topic and t
by galkk 9mo ago
Idk, to me that constant
Result<User, Error>
looks extremely ugly and unergonomic, even just to type.
I understand that this is complicated topic and there were a lot of strong opinions even inside of Google about it, but god, I miss absl::StatusOr and ASSIGN_OR_RETURN. Yes, it won’t work without preprocessor magic (and that’s why this article goes through heavy functional stuff, otherwise it just cannot work in language like C#), but it’s so easy and natural to use in base case, it feels like cheating.
- simonask 9mo agoI think in C# the way to solve this is to have two separate types, `Ok<TValue>` and `Err<TError>`, and provide implicit conversions for both to `Result<TValue, TError>`. The static method approach showcased in the article is really long-winded.
- oaiey 9mo agoYes. Or even simpler, static imported functions. That is similar to how ASP.NET Core handles HTTP feedback. A very common and understood concept. With implicit type parameters this boils down to Ok(4) or BadRequest()
- pyrale 9mo ago> I miss absl::StatusOr Sounds like you would rather have an `ErrorOr<User>` than a `Result<User, Error>`. Both are union types wrapped in a monadic construct.
- galkk 9mo agoI wrote example above: https://news.ycombinator.com/item?id=46508392 https://news.ycombinator.com/item?id=46508392 My point is not the types/monadic constructs, etc (I love to do functional jerk off as a guy next to me, though), but that there are ways to keep code readable and straightforward without neither invocation chains DoOne().OnError().ThenDoTwo().ThenDoThree().OnError() nor coloring/await mess, nor golang-style useless error handling noise
- deleted 9mo ago[deleted]
- moogly 9mo agoIs this similar? https://github.com/amantinband/error-or https://github.com/amantinband/error-or What's some of the "preprocessor magic" that makes this[1] more ergonomic to use? [1]: https://github.com/abseil/abseil-cpp/blob/master/absl/status/statusor.h https://github.com/abseil/abseil-cpp/blob/master/absl/status...
- galkk 9mo agoLook at the long chains of methods in https://github.com/amantinband/error-or?tab=readme-ov-file#no-failure https://github.com/amantinband/error-or?tab=readme-ov-file#n.... The code looks quite unnatural. In google/c++ you can do much simpler, but with preprocessor magic. Example: absl::StatusOr<User> loadUserById(int userId) { ... } absl::Status populateItems(User user, std::vector<Item>& items) {...} absl::StatusOr<Item> findItems(int userId) { ASSIGN_OR_RETURN(auto user, loadUserById(userId)); std::vector<Item> items; RETURN_IF_ERROR(populateItems(user, items)); for (auto& item: items) { ... } } ASSIGN_OR_RETURN and RETURN_IF_ERROR essentially preprocessor macroses, that expand, more or less into. absl::StatusOr<Item> findItems(int userId) { auto userOrStatus = loadUserById(userId); if (!userOrStatus.ok()) return userOrStatus.status(); auto user = *userOrStatus; std::vector<Item> items; absl::Status st2 = populateItems(user, items)); if (!st2.ok()) return st2; } No long and ugly method invocation chains, no weirdly looking code - everything just works. You can see real life example here: https://github.com/protocolbuffers/protobuf/blob/bd7fe97e8c108c9423e413684de8b69adb8365e0/src/google/protobuf/compiler/cpp/tools/analyze_profile_proto.cc#L599 https://github.com/protocolbuffers/protobuf/blob/bd7fe97e8c1... Again, even inside Google there were docs that considered those macroses bad and suggested to write straightforward code, but I'm in the camp who considers them useful and, maybe, sole good use of preprocessor macros that I ever seen, as there are no other way to clearly and concisely express that in majority of languages. F# has something like that with Computational Expressions, but they are still limited.