4 ms·
I think they thought of the standard OOP solution to algebraic data types. Rather than pattern match on the value and then do the work, you dispatch on the valu
by i_don_t_know 10y ago
I think they thought of the standard OOP solution to algebraic data types. Rather than pattern match on the value and then do the work, you dispatch on the value through an interface and do the work. I don't know go so here's some pseudo code:
type Foo = { x : int }
type Bar = { y : string }
interface DoStuff { doStuff() -> void }
function Foo.doStuff() {
...do stuff with Foo.x
}
function Bar.doStuff() {
... do stuff with Bar.y
}
function main() {
value := getSomethingThatImplementsDoStuff()
value.doStuff()
}
Compare this to ML:
type DoStuff = Foo of int | Bar of string
let main =
let value = getSomethingThatReturnsDoStuff ()
match value with
| Foo of x -> ...do stuff with x
| Bar of y -> ...do stuff with y
- brandonbloom 10y agoIndent 4 spaces for code. Here's another way to do this in Go: func f(obj interface{}) { switch obj := obj.(type) { case Foo: // Do stuff with obj.x case Bar: // Do stuff with obj.y default: return fmt.Errorf("obj is of unexpected type: %T", obj) } }
- i_don_t_know 10y agoThanks for the formatting help!
- weberc2 10y agoUnfortunately, this makes a runtime error from something that could be caught at compile time.
- adrusi 10y agoIt's possible to make closed interfaces in Go (give it an uncapitalized method), so there could be a compile-time warning when you don't handle all possible cases in a type switch on a closed interface.
- weberc2 10y agoMaybe this is possible (and I'm not sure it is--this seems like the sort of thing struct embedding would break), but it still doesn't fix that interfaces incur an alloc. Further, it's a shame to abuse interfaces like this; it's not very ergonomic to define a method on a type to denote its membership in a set when we could do something like `type Foo enum { int, Bar, string, []byte }`. None of this is to say implementing real enums in the language is an easy endeavor; only that interfaces are a poor substitute.
- jerf 10y agoIt is possible, and struct embedding does not break it because struct embedding only enables composition. There is no inheritance, so you can not embed a struct that has something private in it and then "inherit" it and override the private stuff. There is no such thing as inheritance in Go. You can "decorate" methods (in the GoF patterns sense), but the internal implementation that you are decorating only gets the instance of itself, not the decorating class. I'm not addressing your other points, just your first sentence, since that is a matter of fact I can concretely address.
- weberc2 10y ago> struct embedding only enables composition Not sure what you mean here. Struct embedding is composition. It enables delegation of methods, which allows the outer struct to satisfy the same interfaces as the inner struct. This necessarily means you can't create closed interfaces. See for yourself: https://play.golang.org/p/akn9rir5of https://play.golang.org/p/akn9rir5of This holds even if the outer and inner structs are defined in different packages.
- deleted 10y ago[deleted]
- jerf 10y agoThis actually sent me down quite the path of discovery, which yielded to me a couple of surprises which I may have to document somewhere else. But the answer to your question is that you can seal an interface by declaring a private interface that has a private method. If you do that, nobody can construct any type that will implement that, even if they peek in the module and look at the private method name. The compiler will yield up something like: src/b/b.go:16: cannot use b (type B) as type a.private in argument to a.CallPrivate: B does not implement a.private (missing a.privatemethod method) have privatemethod() want a.privatemethod() A public interface with a private method does behave a bit interestingly. You can create new structs that compose in the implementation, and if you have a function (not method, function) in the private package that tries to type match on them, it can indeed end up with a type unknown to your package. However, you still have not necessarily "opened the interface" because it remains impossible to ever call a private method on that interface that was not defined in the original package. I haven't tested what public methods do. I was able to construct a struct that in some sense had two different methods which could both be called under different circumstances with the same short method name, which is a bit weird. So, in Go, you can completely close an interface such that you'll never get a type you don't expect, or you can close an interface in a way that means you may get an underlying type you didn't expect but the method will still be guaranteed to come from your package.
- pcwalton 10y agoThis is basically the expression problem: https://en.wikipedia.org/wiki/Expression_problem https://en.wikipedia.org/wiki/Expression_problem The expression problem is motivated by the fact that the OO style (which Go favors via interfaces) makes adding new cases easy (just add another subclass) but adding new methods hard (you have to modify every subclass), while the pattern matching style makes adding new methods easy (just add another match statement) but adding new cases hard (you potentially have to modify every match statement in the program). Depending on the task at hand, either one may be more advantageous. The solutions to the expression problem are attempts to get the best of both worlds. A lot of programming language designs deny that this is a tradeoff, which I think is misguided. Sometimes it's more convenient to be able to add methods easily, and sometimes it's more convenient to be able to add cases easily.
- treehau5 10y agoMy understanding is go's interfaces is counter to OO style. It's about behavior, not objects, plus by recommending to users that you write the smallest possible interface as you can, and then compose other interfaces out of those smaller one's, you reduce the surface area of where the expression problem can come into practice!