4 ms·
> the compiler doesn't help you find the old type-switches that need new branches Presumably you're adding to a "closed" set of types, so it's quite easy to gr
by brandonbloom 10y ago
> the compiler doesn't help you find the old type-switches that need new branches
Presumably you're adding to a "closed" set of types, so it's quite easy to grep for the type names in that type set. I just don't find this to be that much of a problem in practice. Never mind the fact that wildcard clauses exist and so this problem comes up in ML/Haskell/etc as well, since the compiler will consider those patterns exhaustive.
> only allow switching on the variant
Go already has this. It's called type-switch:
https://golang.org/doc/effective_go.html#type_switch https://golang.org/doc/effective_go.html#type_switch
> one can pattern-match using the names of fields
Of course they can, but traditional algebraic data types impose order on to fields, which is an undesirable feature IMHO. However, field dispatch loses the nice order-independence attribute.
- dbaupp 10y ago> Presumably you're adding to a "closed" set of types, so it's quite easy to grep for the type names in that type set Yes, that's an option, but it's not nearly as nice as the compiler automatically telling you what's up, nor does it help downstream users of a library that adds a new possibility. They just have to hope the change is communicated to them. > Never mind the fact that wildcard clauses exist and so this problem comes up in ML/Haskell/etc as well, since the compiler will consider those patterns exhaustive. This is an explicit vs. implicit situation: by using a wildcard, the programmer has explicitly chosen to give up some compile-time assistance, whereas Go implicitly makes this choice for the programmer. > Go already has this. It's called type-switch: ... I don't see how a facetious response like this is at all helpful. The downsides of type-switch are exactly what we're already discussing. > traditional algebraic data types impose order on to fields, which is an undesirable feature IMHO Go is its own language, and can choose to adopt/adapt features to suit its idioms. Referring everything back to how "traditional ADTs" work seems silly when there's trivial tweaks that fit Go better. > However, field dispatch loses the nice order-independence attribute. I don't know what you mean by this (I can guess, but I don't see how it relates to naming fields in patterns), could you rephrase?
- brandonbloom 10y ago> nor does it help downstream users of a library If you add a new type to a sum type in a statically typed language, that's a breaking change for all downstream consumers. Again, you may view this as a benefit (clients get compiler errors about new cases to handle!), but I view it as a drawback (clients can't upgrade until they handle all new cases!). > Go implicitly makes this choice for the programmer And I believe that Go (and Clojure, which omits both types and pattern matching for reasons including those I'm discussing) makes the right decision for the programmer, as openness to future changes without breakage is better > 90% of the time. > could you rephrase? You said "one can pattern-match using the names of fields", I took that to mean matching on something like Foo{x: 5}. If you do that and also have a clause Foo{y: 10}, now you have ambiguity and the order you compare x==5 or y==10 first matters, since you might have an object Foo{x: 5, y: 10} which would match both clauses. If you just meant that you could do Foo{x: x} with blanks, that's fine, we're in agreement then. Clojure offers {:keys [x]} in destructuring for this purpose, and it's great.
- bsaul 10y agoImagine an enum describing the various states of a state machine. I'd definitely prefer the compiler to refuse compiling, rather that hoping to be future proof by ignoring a new state.
- dbaupp 10y agoFor both of the first points: I don't think anyone's proposing that closed sum types be the only polymorphism in Go (removing the existing open polymorphism would be a wild breaking change and so isn't even a remote possibility), so this would be a feature for when alerting consumers that something has broken is good. When flexibility is what your library needs, use interfaces, when reliability (or performance[0]) is what it needs, use ADTs. One argument against adding the new feature is it forces people to think about which to use, and they may choose an inappropriate one. (This choice argument is far stronger than vague concerns about the feature possibly resulting in breaking changes.) In any case, libraries can already make breaking changes, and presumably quite a few want to/do (so it's not like having a feature that can also result in breaking changes is anything new), and, adding a new type to existing open set can easily be a semantic breaking change that stops code from running correctly, even if it doesn't stop code compiling. > You said "one can pattern-match using the names of fields", I took that to mean matching on something like Foo{x: 5}. If you do that and also have a clause Foo{y: 10}, now you have ambiguity and the order you compare x==5 or y==10 first matters, since you might have an object Foo{x: 5, y: 10} which would match both clauses. No, that is orthogonal, as I also discussed in my original reply. I was visualising something like `Foo { x: binding }` in the pattern, which would make the value of the x field available under the name `binding` (and, for convenience, `Foo { x: x }` case could be allowed to be abbreviated to `Foo { x }`). Whether the binding on the right-hand side of a field allows pattern matching or not is its own discussion. [0]: ADTs aren't forced to allocate, and possibly use a more efficient switching scheme (it's just an integer for an ADT; I don't know the implementation details of Go's type-switch so it might be that fast).