4 ms·
To expand, Go's type system is relatively rudimentary. The lack of option types[0] leads to this fairly common, verbose Go pattern: func DoFoo(Foo foo) Cat
by wting 13y ago
To expand, Go's type system is relatively rudimentary. The lack of option types[0] leads to this fairly common, verbose Go pattern:
func DoFoo(Foo foo) Cat {
bar, err := GetBar(foo)
if (err != nil) { return nil }
baz, err := GetBaz(bar)
if (err != nil) { return nil }
cat, err := GetCat(baz)
if (err != nil) { return nil }
return cat
}
Option types add metadata to a type, essentially combining `bar` and `err` into a single variable. Let `Maybe x` mean a function will return `Something x` or `Nothing`. For example (in hypothetical Go):
func DoFoo(Foo foo) Maybe Cat {
bar := GetBar(foo)
if (bar.(type) == Nothing) { return Nothing }
baz := GetBaz(bar)
if (baz.(type) == Nothing) { return Nothing }
cat := GetCat(baz)
if (cat.(type) == Nothing) { return Nothing }
return cat
}
Since this is such a common pattern, Haskell has a bind operator (`>>=`) to take advantage of option types by passing the output as the input of the next function if it's a `Something`, or return `Nothing`.
func DoFoo(Foo foo) Maybe Cat {
return GetBar foo >>= GetBaz >>= GetCat
}
If you care about why something failed, use an `Either` instead of a `Maybe`. In a language that supports algebraic data types, you could create your own sum type instead.
[0] https://en.wikipedia.org/wiki/Option_type https://en.wikipedia.org/wiki/Option_type
- jbooth 13y agoNow you've got way less code, and way more cognitive load per line. There's a reason why hideous Java is so successful while beautiful Haskell is a punchline to jokes.
- wting 13y agoMany languages besides Haskell have option types (Rust, Scala, OCaml, Java 8): http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html http://www.oracle.com/technetwork/articles/java/java8-option... Using option types produces more robust code and prevents null pointer exceptions / segfaults. Go's idiom of multiple return values and error is a poor man's Either, which is an improvement on C's return code idiom[0]. [0] C's return code idiom led to the latest GnuTLS bug: http://blog.existentialize.com/the-story-of-the-gnutls-bug.html http://blog.existentialize.com/the-story-of-the-gnutls-bug.h...
- jbooth 13y agoYes, but reading code is much more important than writing it in most contexts, and you're not limited by typing speed anyways. The one-liner would be harder for me to unpack, in most situations, than a 3-liner. You've got 3 calls, give me space to work with them.
- copergi 13y agoThey don't need to be on one line. If you really want to pretend that having them on one line is a problem, then put them each on their own line. You can even be needlessly verbose if you want to: do a <- GetBar foo b <- GetBaz a c <- GetCat b return c
- jbooth 13y agoThat's much more to my liking, but still, we've got multiple ways of doing option types and now I've seen 2 different operators, which I presume are overloaded to deal with those types somewhere? Or we're dealing with a ton of built-in types and built-in operators to deal with them? I'm not trying to sell anyone, code however you like -- I prefer the situation of "simpler environment, don't write bugs" to "really complicated environment that makes it theoretically impossible to write bugs". I bet I can still write bugs.
- copergi 13y ago>now I've seen 2 different operators, which I presume are overloaded to deal with those types somewhere? Or we're dealing with a ton of built-in types and built-in operators to deal with them? No. Remember we're talking about using a language that is not broken by design instead of go. You have one operator (>>=) and it works on one typeclass (Monad). Do notation (do and <-) is merely syntactic sugar that desugars to using >>=. >I prefer the situation of "simpler environment, don't write bugs" to "really complicated environment that makes it theoretically impossible to write bugs" And since those are not the options available, people tell you that those are not the options available. Doing it right is very simple. Your options are "simple and with lots of chances to create bugs" or "just as simple but with fewer chances to create bugs".
- Silhouette 13y agoNow you've got way less code, and way more cognitive load per line. To someone who isn't familiar with that particular idiom, perhaps it causes more cognitive load at first. Sometimes you have to learn new ideas and techniques to make the best use of your tools. On the other hand, once you are familiar with the idiom, what you see there is a concise and easily readable representation of the main algorithm, together with a quickly recognisable, robust way of dealing with the edge cases. Would you also object to someone using structured programming because it causes way more cognitive load than just writing goto everywhere?
- pcwalton 13y agoIn a language with option types (such as Rust) if you want to be totally explicit and write your error handling the Go way, it's scarcely more verbose than it is in Go, and totally clear: let foo = match some_call_that_may_fail() { Ok(foo) => foo, err => return err, }; The advantage is that the language forces you to handle errors: dropping the error on the floor is quite hard to do, whereas "foo, _ = some_call_that_may_fail()" is very easy in Go. (And if the call doesn't return any value at all except an error, you don't even have to write the "foo, _ =" bit; this is a nasty gotcha and is why external lint tools like errcheck are needed for Go.)
- jbooth 13y agoI really can't wait to spend more time learning Rust, but that bit you just put out strikes me as a fair bit more complex than just multiple returns plus "don't ignore your errors, dude, you crazy?". We've got the let-match func() {} construction, the Ok() function (built-in? library?), the => foo vs => return err.. that's returning from the outer function, right? Whereas the => foo completes the let and continues? There's a lot going on in there. I haven't spent any time using Rust, though, so maybe that construction will seem more natural when I get around to doing that. Anyways, someone upthread called Go 'simplistic' which has both positive and negative connotations, and I totally agree. I'm happy with a simpler setup that solves 80% of problems really well and maybe there are some pitfalls you can fall into if you don't check your error values. As long as I'm not completely hamstrung by the simplicity (generics would be nice), I find the lack of features to be a win when you add up all the non-features that I don't have to think about it.