5 ms·
It'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 cas
by adrusi 10y ago
It'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.
- weberc2 10y agoI believe that you can seal an interface by making it and its method(s) private, but that doesn't do us much good because we're talking about using this to build something that looks like an enum (complete with compiler warnings when we fail to address a branch in a type switch). If you only intend to use your "enum" in the package, then the interface isn't sealed in the scope you want to use it. If you want to use the enum outside of your package, then you can't use the private interface at all. So you can create a "sealed interface" only in the sense that you can't use it at all outside of its defining package, and it won't be sealed inside of its defining package. I can't see a way to build an enum from this in the way the OP described.