6 ms·
Yes please! I really dislike every golang function returning "foo*, error" when it really means either foo or an error.
by kadoban 5y ago
Yes please! I really dislike every golang function returning "foo*, error" when it really means either foo or an error.
- feffe 5y agoSum types would be nice to describe protocols such a grpc as well (given suitable syntactic sugar to switch on them). I think sum types, possibly in combination with tuples would have been nicer than multiple return values. But I guess everyone has their particular wish list of what a programming language should be :-)
- pkaye 5y agoSo why not use Rust instead since it already implements sum types?
- deleted 5y ago[deleted]
- ziml77 5y agoBecause Rust throws out the GC which means that you have to deal with complexities of lifetime management. (I don't agree that sum types should be added to Go, as much as I dislike the language as it is)
- BenFrantzDale 5y agoAs someone coming from C++ I don’t comprehend this complaint. How do you even do anything in a language without deterministic destructors? All my experiences with garbage collection have been painful. RAII is so much easier to use.
- azth 5y agoFor resource management, Java/C# have try-with-resources/using statements. Python has `with`, golang has "defer". GC addresses other issues like memory sharing, cyclic data structures, etc.
- tialaramex 5y agoThey said they liked sum types, that doesn't automatically mean they want to learn Rust. I liked the STL containers when I read about them in the 1990s, but I don't like C++ and the existence of the containers did not change that.
- kadoban 5y agoBecause I have a job and am not yet a dictator at my company for technical decisions.
- Andys 5y agoWon't the generics feature type sets fulfill this use case?
- xh-dude 5y agoI feel like an object lesson here would be context.Context in Go, which sort of rhymes with Result types in a way … I figure this sort of programming in Go post-generics won’t emerge as uniform baseline but thematic variations will arise in some particular domains. But I really don’t know.
- akira2501 5y agoMany functions return foo AND the error. This is occasionally very useful.
- kadoban 5y agoOcassionally, but pretty rarely in my experience. Both types of functions should exist, it should not be so hard to return an either/or.
- tialaramex 5y agoThat's not an error then, or, that's not what I'd consider a result, or both. Compare Rust's https://doc.rust-lang.org/std/str/fn.from_utf8.html https://doc.rust-lang.org/std/str/fn.from_utf8.html If you've got a buffer full of bytes, which you hope are UTF8 text but maybe aren't, call std::str::from_utf8 and you either get back a string slice with your text in it, or you get a std::str::Utf8Error structure which explains what the problem was in an actionable format. You can write code to process this Utf8Error and your bytes - maybe you're reading blocks of data and it's all valid UTF8 but the last character is continued in the next block for example, you can discern that from Utf8Error and just turn the valid part into UTF8 and keep the rest until the next block is available.
- baby 5y agoNot an error then, it doesn't make semantic sense.
- __s 5y agoWhen it's occasionally useful return (type, err), but generally the two results are distinct so there's no need to return two results in the general case when one suffices Indeed, I recently updated some code to return a relevant value in the error case: https://github.com/wal-g/wal-g/pull/1143/files#diff-d896e5d50cc3693c055fd9a6cfbfaccd1cc82fc3aaea3881c38cf9eb15a63b50R240 https://github.com/wal-g/wal-g/pull/1143/files#diff-d896e5d5... where true means the error is rooted in a corrupted page, & false means that the error isn't due to a corrupted page. It does feel a little dirty & a comment is probably necessary to make this case clear Still, Result can work here. For example, Rust's binary_search https://doc.rust-lang.org/std/vec/struct.Vec.html#method.binary_search https://doc.rust-lang.org/std/vec/struct.Vec.html#method.bin... which returns Ok(idx) when that's the location of the element, or Err(idx) when that's the location the element would be if it were there (this can be a bit annoying when you just want to insert, since you end up writing `let idx = match result { Ok(idx) => idx, Err(idx) => idx }`)
- bborud 5y agoI disliked it initially. After 5-6 years of using Go as my primary language I’ve come to appreciate it. It is clearer than having to figure out what is returned. And if an error can be returned. It’s easier when it is right there in the function signature.
- Zababa 5y agoThe thing sum types would allow is to make a clear distinction between functions that return either a result or an error and functions that can return both a result and an error. Many functions in Go will always return either res, nil or nil, err. Those functions would benefit from a way to show that in the signature, to differentiate them from the functions that can return res, err at the same time. This is not a replacement for multiple return values, as there are many cases where multiple return value are useful.
- monocasa 5y agoBut a Result<foo*, error> is clearer than foo*, error. I think that's the point the parent is making.
- kadoban 5y agoExactly, at least it's clearer in the vast majority of cases where that's what I actually mean (but golang won't let me encode easily). The way golang ~makes me encodes it makes using these functions annoying, because then you ~need to test for the nonsense cases where you have neither an error or a result, and maybe where you have both.
- bborud 5y agoBut how is it clearer? I can see the point of where you get neither error nor result, but you can get that in both scenarios, so I don't see how anything is gained. And you still have the same burden of checking whether an error condition did arise. That is the bit that usually matters when you call a function: knowing if it has error conditions (many functions don't) and checking if/what they are. I don't see any practical advantage here. Explain it to me like I'm five :)
- Ciantic 5y agoThat's right. This is about the language too, if Go doesn't have pattern matching, using sum types (or tagged unions) is a bit gnarly. This is the reason for instance in C# Hot Chocolate GraphQL library the newly proposed return type for fallible mutations is, e.g. for hypothethtical register function: { user: Option<User>, errors: [Errors] } Instead of more type-correct way of: union result = user | Errors Precisely because using unions is gnarly in JS who are the main consumers of the API. Similarly if GO doesn't have a way to pattern match, the actually using sum types is very annoying and this "foo*, error" can be seen as more convinient.
- Zababa 5y agoThe problem here is not the absence of pattern matching, it is the absence of the "tag" part of tagged unions. Union types like the one you presented (union result = user | Errors) are different from sum types, as they don't have a tag. Without the tag you need a way to know the type of the result at runtime. For example in TypeScript, you can use a type assertion and control-flow analysis to emulate sum types and pattern matching: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types https://www.typescriptlang.org/docs/handbook/2/everyday-type.... While sum types and union types are close, they are not exactly the same. Let's take an example: union bools = bool | bool enum Bools = A(bool) | B(bool) The example is a bit weird but shows an important point: bools has 2 values, true and false. Bools has 4 values, A(true), A(false), B(true), B(false). In bools (the union), true and true is always the same. In Bools (the sum/enum), A(true) is not the same as B(true). I don't know enough about type theory to know if union types have a relationship with sum types. They can be used the same for most cases but they have differences around the edges.
- Ciantic 5y agoYeah I was a bit sloppy when I wrote my answer. With GraphQL you can mimick tagged unions by giving each branch an object type. I actully wrote just few days ago about how cool it would be if TypeScript-like language too had tags: https://github.com/Ciantic/thoughts/blob/master/2021/dynamic-language-with-tagged-unions.md https://github.com/Ciantic/thoughts/blob/master/2021/dynamic...