4 ms·
The problem is that it's so incredibly inflexible and dated. Many effectful actions e.g. reading from a file system can have a range of different errors each o
by threeseed 3y ago
The problem is that it's so incredibly inflexible and dated.
Many effectful actions e.g. reading from a file system can have a range of different errors each of which you want to handle differently e.g. out of disk space versus lack of permissions.
It's great that you're treating errors as values. But you need pattern matching and other techniques as they make your code more: (a) readable, (b) safer, (c) simpler and (d) less verbose.
The hilarious thing is that eventually Go is going to get these because there is nothing but upside. And then at that point you're going to wonder how you ever survived without it.
- Kamq 3y ago> But you need pattern matching and other techniques... The go way to do this would be: switch { case errors.Is(err, outOfDiskSpaceError): // handle out of disk space error case errors.Is(err, lackOfPermissionsError): // handle lack of permissions ... default: // do the equivalent of the `_` case in a scala match statement or `t` in a lisp cond } Which is roughly as readable as scala/rust's match statements. Moreso if someone tried to get cute in scala and bind both the object as a whole and parts of it at the same time ( something like `case x @ Type(_, _, y, _)` ) or when people get real cute with the unapply method. I mean, I like scala. It's fun. But I would never say it's more readable than go. I've been left to support things that happen when a team of average intelligence devs get a hold of it. You're also really comparing an MIT and New Jersey style solution here, and judging them both on MIT merits. And I don't think that's exactly a fair argument.
- blueberry87 3y agoTrying to compare a switch statement to proper pattern matching is like comparing a rock to a rocket.
- di4na 3y agoI am unashamedly stealing this one, it is both apt and making me smile. Kudos
- rob74 3y agoIf you're thinking of C/C++ switch statements and everyone that blindly copied them (looking at you Java, JS and PHP), you're right, but Go's switch is much more flexible (https://gobyexample.com/switch https://gobyexample.com/switch). PHP tried to correct the mistake of not giving some more thought to the switch statement at the beginning by including a new "match" expression in PHP 8 - fun times for everyone who used classes called "Match"...
- pjmlp 3y agoNowadays Java and C# switch are almost as powerful as Standard ML match.
- wholesomepotato 3y agoIt's still a rock. Play with a language with proper pattern matching, Rust, Haskell, Ocaml, Scala, and you will also see it's just a rock.
- lelanthran 3y ago> Trying to compare a switch statement to proper pattern matching is like comparing a rock to a rocket. Yeah, but when you need to bash someone over the head, the rocket suddenly isn't any use anymore. IOW, sometimes the simpler thing is better. In fact, in practice, the simpler thing is usually better... Like, rocks are usually more useful to the average person than rockets are.
- Kamq 3y agoGo's switch statement is closer to lisp's cond expression, except it doesn't evaluate to a value.
- kazinator 3y agoA switch or case statement is a restricted form of pattern matching for simple values. It fits those use cases, which are frequent. I use a language that has both pattern matching and case constructs. I use both. If you're doing complex pattern matching all over the place (especially matching the same sets of cases repeatedly in multiple locations in the code), maybe your design sucks. It's not making effective use of OOP or some other applicable organizational principle.
- marcus_holmes 3y agoI don't understand why pattern matching is seen as more readable, safer or simpler. Why do you think this?
- macintux 3y agoPattern matching in Erlang is a brilliant feature. You get concise branching and binding, and if a pattern match fails the native error handling (dramatically less verbose than Go) takes care of things for you (mostly). Much like other FP features, shoehorning pattern matching into a language doesn't give you nearly the same advantages as building a language around it, so I don't know that it would make Go significantly better.
- marcus_holmes 3y agoI find it really, really hard to work out which pattern is matching when debugging Erlang. It might be more concise but it's massively less readable (and less amenable to reasoning out what might be going wrong). Especially in older code bases that have had a few people work on them.
- justinpombrio 3y agoCompare: struct BinaryTree { leaf_value: int, left_child: BinaryTree, right_child: BinaryTree } function sum_leaves(tree: BinaryTree) -> int { if tree.left_child != nil { return sum_leaves(tree.left_child) + sum_leaves(tree.right_child); } else { return tree.leaf_value; } } vs: enum BinaryTree { Leaf(int), Branch(BinaryTree, BinaryTree) } function sum_leaves(tree: BinaryTree) -> int { match tree { Leaf(leaf) => leaf, Branch(left, right) => sum_leaves(left) + sum_leaves(right) } } (If you're thinking "the first example should be using inheritance + polymorphism", imagine that "BinaryTree" is in a different library than "sum_leaves". If you're now thinking "visitor pattern", sure, go write your hundreds of lines of boilerplate code if you like.) The first example is less safe because it's filled with invariants: left_child is nil iff right_child is nil, and leaf_value should only be accessed when they're nil. The second example has zero invariants. (You might think there would be an invariant that the children aren't nil, but languages with pattern matching tend to use Optional instead of nil, so that invariant isn't necessary.) If you make mistakes about when you access various fields in the first example, you'll be accessing leaf_value when it's uninitialized, or get a null dereference from one of the pointers. As for readability, that's in the eye of the beholder, but I find the second example a lot more readable for the same reason: it's clear in both the data definition and the use site which fields exist. All sorts of details vary across languages, even with a small example like this, but that's the basic differences.