5 ms·
Much more interesting (first language spec commit): https://github.com/golang/go/commit/18c5b488a3b2e218c0e0cf2a7d4820d9da93a554 https://github.com/golang/go/co
by dantaylor08 10y ago
Much more interesting (first language spec commit): https://github.com/golang/go/commit/18c5b488a3b2e218c0e0cf2a7d4820d9da93a554 https://github.com/golang/go/commit/18c5b488a3b2e218c0e0cf2a...
- dilap 10y agoI wonder why they got rid of this one > - new methods can be added to a struct outside the package where the struct is declared (need to think through all implications)
- ecnahc515 10y agoI'd have to guess it would be conflict resolution. Imagine two separately imported packages for which you didn't write that add a method in on a type from a third package you didn't write, all with the same name/method signature. How does the compiler you know which of the implementations to use?
- junke 10y agoCompiler warning. --- (edit) The example, while being possible, looks quite improbable. If it is only a matters of conflicting names, qualified names should be able to resolve the ambiguity; here I suppose you imagine implementing the same interface for the same type differently in two packages. That a package implements an interface for the same external method for a third-party type is already dubious. Now, you have two packages like this and you want to import them both. That's quite a corner case. Practically, the last package that is imported could "win" (so you can decide which you want). The compiler has to register all the possible implementations anyway, so a warning is trivial to emit on redefinitions. ---- I'd guess the restriction is to allow compilation of dynamic dispatch on a package basis (think separate compilation) instead of waiting till all possible files have been processed.
- junke 10y agoI mean dispatch in general, not necessarily dynamic dispatch.
- dilap 10y agoYeah, good point. Though it would be handy if you could at least within your own package add methods to types. But then I guess those methods would be uppercase but not exported, which would be weird. You can certainly imagine schemes like specifying in the import which types to extend, but that seems complex enough that I'm not surprised a language as radically devoted to simplicity as Go left it out.
- ori_b 10y agoIt's hard to compile efficiently, because you need to efficiently do the method lookup in the implementation.
- 4ad 10y agoIt doesn't work well with interfaces. A method defined in a new package might break a type switch (or some reflection-based code) in another package. Plus it's unclear what should happen with interfaces when multiple packages define methods with the same name.
- junke 10y ago> A method defined in a new package might break a type switch (or some reflection-based code) in another package. In that case the code would break because it assumes too much. If the language was designed differently, people would code differently too. This is like having a Java abstract class which "knows" all the possible subclasses in advance: if it breaks, it is the responsibility of that abstract class for having too much coupling. > Plus it's unclear what should happen with interfaces when multiple packages define methods with the same name. I am not sure I understand: if methods are defined in different packages, they have different qualified names, don't they? is there any ambiguity here?
- 4ad 10y ago> In that case the code would break because it assumes too much. If the language was designed differently, people would code differently too. Sure, but we want interfaces to work the way they work now, because it's useful and reduces coupling. > This is like having a Java abstract class which "knows" all the possible subclasses in advance: if it breaks, it is the responsibility of that abstract class for having too much coupling. The analogy is not very apt, because in Go code the consumer is the one which is broken, not the producer. In the current design the consumer can make static assumptions about code, if those assumptions are helpful. This works because the assumptions don't change when new packages are imported. In other words, they work because the coupling is known and stable. You know exactly what a type is because its definition is only in a single package, the one you import. If you could define methods anywhere, you introduce hidden dependencies and more coupling. A new package might change the nature of the type. This is not acceptable. Of course people would write code differently if this weren't the case, but then the language would be less useful. > I am not sure I understand: if methods are defined in different packages, they have different qualified names, don't they? is there any ambiguity here? No, they don't have different qualified names. package foo import ( "fmt" "numbers" // type T int is defined here ) type Hexer interface { Hex() string } func PrintHex(v interface{}) string { switch vv := v.(type) { case Hexer: return vv.Hex() case numbers.T: return fmt.Sprintf("%x", vv) default: return "unknown" } } PrintHex(T(42)) will return "2a". Now what happens when you import ( "bar" "baz" ) where (in a hypothetical version of Go): package bar import ( "fmt" "numbers" ) func (t T) Hex() string { return return fmt.Sprintf("0x%x", t) // notice the 0x } and: package baz import ( "fmt" "numbers" ) func (t T) Hex() string { return return fmt.Sprintf("0x%X", t) // notice the 0x and CAPS } What will PrintHex(T(42)) return? "2a", "0x2a", or "0x2A"?
- django1993 10y agoMaybe because structs have some fields private and some public. To add a method outside the package would be to make those private fields visible in the method outside the package which then allows such methods to manipulate the struct and that will break the abstraction provided by it.
- junke 10y ago> ... would be to make those private fields visible in the method outside the package. Since you write the implementation of the method inside your struct's package, you have the right to manipulate private data there as you would do with any function. I don't understand the problem.
- tqkxzugoaupvwqr 10y agoI think the problem they wanted to avoid is incompatibility (Go cares much about compatibility, see Go 1’s Promise of Compatibility[1]). Private fields mean to external packages “This is non of your business. The field can change or be removed at any time without notice.”. If external packages could add methods to a struct, thus turning private fields into effectively-public fields, the whole struct (all its fields) potentially becomes public. How do you maintain a package if your defined API (public fields/methods) is ignored and instead everything is made available to external packages? To keep compatibility, you could never refactor the package, instead you have to keep all private fields to not break external packages that use them. [1] https://golang.org/doc/go1compat https://golang.org/doc/go1compat
- junke 10y agoThere is no need to bring private fields too. Just keep the same visibility rules. The new method would be written inside a user package which would have access only to the public members of the type being dispatched on. That mean that you could only define methods for external structs that make use of their public API.
- Xlythe 10y agoYou could just let the external methods only access public variables. That's exactly what Java let's you do when you extend another class. I agree that private members should stay private. I wish I could add methods from outside of my package. I currently run into cyclical dependency issues when I try and define something like... func (g Game) GetPlayers() []Player { ... } func (p Player) GetGame() Game { ... } While having Game and Player in separate packages. It's not the end of the world having them in the same package, but the amount of methods does pile up...
- burrows 10y agoThe first page of commits https://github.com/golang/go/commits/master?page=833 https://github.com/golang/go/commits/master?page=833
- M4v3R 10y agoAnd here's probably the first tree that contains actual source code: https://github.com/golang/go/tree/cb87526ce3531557ccf69969de4c8018956b10b5 https://github.com/golang/go/tree/cb87526ce3531557ccf69969de...