3 ms·
The presenter has discovered the Result / Either monad at 00:24:16, but their proposed C implementation sounds like a really bad idea: - The flag needs to be m
by Arnavion 6y ago
The presenter has discovered the Result / Either monad at 00:24:16, but their proposed C implementation sounds like a really bad idea:
- The flag needs to be manually inlined into every type, thus bloating the type even after the value has been successfully created. ie every instance of `file_contents_t` in your program has become the equivalent of `Result<file_contents_t>` and you have to check it for validity every time you use it, not just when you create it.
- The flag is easy to forget to check. `std::optional` has that problem too with its `*` and `->` operators, but at least you have to write them, as well as the type "std::optional", explicitly. You can't accidentally use a `std::optional<file_contents_t>` as a `file_contents_t`, but you can accidentally use a `file_contents_t` with `.valid = false` where one with `.valid = true` was expected.
- The `img = crop_to_cat(img); img = add_bow_tie(img); ...` example looks great when you just call the functions in sequence and expect each function to be a no-op for invalid inputs. But this breaks down when you have loops or logging or sleeps or other side effects that you genuinely want to skip. At that point you will have to start checking `if (img.valid)` manually again anyway. And if there are enough of these scattered around multiple scopes, you'll end up wanting `goto error` again.
The callback-based example with `std::optional` as well as the Rust example with early returns don't have these problems. (Incidentally the Rust version uses an explicit `match` and manual return of the error for some reason, even though that particular usage pattern is exactly what the `?` operator is for.)
- enqk 6y agoHaving used the “local errno” solution, I feel you’re overstating the downsides a great deal.
- dthul 6y agoI agree. `crop_to_cat(img)` now has to be concerned with handling a possibly invalid image even though this method doesn't make sense for an invalid image. It muddies the type signature of the method and instead of `Image -> Image` (or possibly `Image -> Either Image Error`) it has to read `Either Image Error -> Either Image Error`. What if I want to apply that method to a valid image? I either need to wrap the image or provide different overloads of the method which can get quite tedious if the number of possibly "fallible" parameters grows. A macro for unwrapping and early return would be nicer.
- amadvance 6y agoNot to mention that you also lose the error context. That boolean "is_valid" flag is not really informative of what happened. For example, if the image to load doesn't exist, you may want to print/log such path. The goto looks like a better approach.
- flohofwoe 6y agoYou can just as well use a nested common error struct which has more detailed error information instead of just an "is_valid" bool, and also turn the whole return value into a tagged union to save some space (so the return value either contains a success value, or error data, but not both). You just don't have the high-level syntax sugar to create or deal with tagged unions in C.
- DougBTX 6y ago> thus bloating the type Mildly off-topic, but as of Rust 1.50 [0], Option<File> is now the same size as File, as "-1" can be used to represent no-file. You're completely right though about how it would be good to unwrap it as soon as possible once it is successfully created... [0] https://blog.rust-lang.org/2021/02/11/Rust-1.50.0.html#a-niche-for-file-on-unix-platforms https://blog.rust-lang.org/2021/02/11/Rust-1.50.0.html#a-nic...