Then make a Draw() method on the single object default to what you expect. The simple inline explanation is:
type SingleObject struct {
Cowboy
Shape
}
Access is as follows to be unambiguous: Woody.Cowboy.Draw()
Woody.Shape.Draw()They all are the same interface and can be passed into each other's methods, leading to a logical error.
Yes, sometimes this isn't an option when you want to satisfy the interface for two different libraries, but I've not seen this occur very often. More likely you're in control of one of the interfaces; so rename your method to be more descriptive.
This is assumed in the description of the problem. Go has no solution for it. (Java doesn't either, but this is one of the things that C# got right over Java; it's unfortunate that Go has the same issue.)
> , but I've not seen this occur very often.
Sure, it's a problem in theory. Whether it's a problem in practice is a different question. I'd be interested to see examples of this problem in the wild.
http://stackoverflow.com/questions/2598009/method-name-colli...
http://stackoverflow.com/questions/4033329/multiple-interfac...
http://stackoverflow.com/questions/11343238/java-implementin...
http://stackoverflow.com/questions/17484325/implementing-mul...
http://stackoverflow.com/questions/9863835/two-interfaces-wi...
http://stackoverflow.com/questions/19959371/calling-same-met...
http://stackoverflow.com/questions/14290902/multiple-interfa...
etc. etc. I got bored after the first page of Google results :)
> I encountered such a case where a legacy "Address" class implemented Person and Firm interfaces that had a getName() method simply returning a String from the data model. A new business requirement specified that the the Person.getName() return a String formatted as "Surname, Given names". After much discussion, the data was re-formated in the database instead. – belwood
Further down someone hit a similar issue with the getString() method in some of the Android frameworks.
Even so, this problem could still have been fixed by just renaming the method to be more descriptive because they were still designing it. The only time this would be a problem in Go is if you had two unfortunately and oddly named methods in two libraries where you can't control either.
Edit: And to take it a step further, I would say that since interfaces are Go's only resource for representing generic behavior, go developers are more mindful of the methods they add to interfaces, in both number and descriptiveness.
How else do you write a function that can take multiple types of structs, all of which have a Name field, and select that field? (Other than reflection.)
I mean, there are a bunch of Go packages that have types with a method named precisely that: https://www.google.com/search?q=golang+"getname"
> Even so, this problem could still have been fixed by just renaming the method to be more descriptive because they were still designing it. The only time this would be a problem in Go is if you had two unfortunately and oddly named methods in two libraries where you can't control either.
Like in the Android case mentioned above? The Android system frameworks required a getString() method, while the MVVM library the commenter was using required an incompatible getString() method. Neither could be changed without a lot of headache.
> How else do you write a function that can take multiple types of structs, all of which have a Name field, and select that field?
That presentation that you linked to says to use struct embedding aka composition. And if you don't want to do that then I'd say you're "probably" framing the problem wrong, but we really need a more concrete example to discuss this further otherwise we'll just be talking past each other.
You can see this through the lens of i.e. Peter Norvig writing a Sudoku solver vs. that object modeling guy, or you can look at it through the lens of "the language should capture problems as safely and completely as possible".
You can take either perspective too far.
When Pike suggests implementing generics with "go generate", I feel like he's taking it too far. Here, I think maybe we're too far the other direction.
We have at least three examples of this being an actual problem in practice that could not be worked around. Two in Java, and one in Golang itself. I don't know how you can come to the conclusion you did.
In particular, "struct composition" does not solve the problem any more than inheritance would in Java. This comes up in cases in which the structs in question have separate declarations and you don't want to force all of your method's callers to inherit from your class/embed your struct just to call your function.
- https://golang.org/pkg/database/sql/driver/#Rows -- Columns is a getter
- https://golang.org/pkg/database/sql/driver/#Stmt -- NumInput is a getter
- https://golang.org/pkg/image/#Image -- ColorModel and Bounds are getters
- https://golang.org/pkg/reflect/#Type -- Align, FieldAlign, NumMethod, Name, PkgPath, Size, Kind, Bits, ChanDir, IsVariadic, Elem, Key, Len, NumField, NumIn, NumOut are all getters
And so on.
The reflect package could, for example, have the Type-returning methods return a struct using structure embedding to handle most of those fields. But they didn't write the API that way, because it would be annoying to do so. So they used interfaces with getters instead. This isn't Java "astronaut" design—it's just how you program in a language with interfaces.
Look at the implementation of PkgPath() for example: https://golang.org/src/reflect/type.go#L446
There's only one implementation of PkgPath(), and it does nothing but address a struct field. The functions could expose uncommonType directly, but they didn't. That's because getters are a common design pattern in Go.
You correctly observe than in order to conform to a Golang interface, struct fields have to be exposed through setters and getters. But all those examples are interfaces, not structs.
The gap between your summary here and the Golang idiom is that Golang doesn't want you to make everything an interface. Generally, Golang interfaces seem to fit one of two molds:
* Interfaces that any systems programmer could predict needing ahead of time, like io.Reader and io.Writer.
* Interfaces that are born "bottom up" to allow for a very specific bit of code reuse.
Golang's standard library does not have a lot of interfaces that are conceived of as hooks for future functionality and opportunities for decoupling, which is a stark contrast from Java libraries, which do.
Does Java tend to use getters unnecessarily where fields could have sufficed? Absolutely. Go does not, and that's a great thing about the language. But I think that's irrelevant to the point at hand about explicit interface names. In none of the cases where the name collision problem was an issue would moving things to fields have helped. For Next() in Golang, it was actually a method with behavior that was causing the problem, not a simple getter. For getName() in Java, the problem was that two different libraries that needed to work abstractly with a user object needed different "views" of the same field to work properly, and there was no way to disambiguate—observe that with fields, you'd have the same problem! Likewise for the Android library. In these cases, you really want explicit interfaces.
The right objection, in my mind, is not "just use fields" but is instead "use the adapter pattern". That is, acknowledge that yes, this is a problem in practice, but when it arises you can just make a separate type wrapping your type and implement different methods on that wrapper. That is indeed a solution that works around the issue. The question from a language design POV is then whether the benefits of structural interfaces outweigh the downsides, one of which is requiring programmers to write adapters to solve name conflicts. Reasonable people can differ on that, and I think it's obvious I disagree with Rob Pike here. But presenting fields as an adequate substitute for getters is inadequate (since you really do need getters), unappealing (since getters are great, which is why Go uses them) and pretty much totally tangential to the problem.
For the record, in Juju we have hundreds of interfaces and hundreds of thousands of lines of code, and AFAIK have never had this be a problem.
For the given Next problem, you can easily make a wrapper type that simply masks the underlying Next() method with its own implementation.
type MyType struct {}
func (m *MyType) Next(i int) {
// do base next stuff
}
type ForSql struct {
*MyType
}
func (f ForSql) Next() bool {
// do sql-next stuff
}
and then using this type is trivial in-code: mt := &MyType{}
doSomeSqlThing(ForSql{mt})
Note that this new type retains all the methods of the original type, so it still implements all the interfaces it used to (unless they rely on the old Next signature).Compare this to the benefits of implicit interfaces (decoupled code, easy composition, using third party code as your own interface type without needing a wrapper type)... hopefully it's pretty obvious this is a large net positive.
I implemented a DB driver that had its own Next() method. Later I wanted to implement the SQL package interface. That interface contains Next() (http://golang.org/src/database/sql/sql.go?s=40568:40595#L157...).
Choices - break backwards compatibility and change the interface I control or convolute the type definitions to create a type specific to the database/sql interface.
This limitation in combination with methods only being distinguished by name, not by parameters, turns out to be very annoying -- especially as interfaces profliferate.
> I implemented a DB driver that had its own Next() method. Later I wanted to implement the SQL package interface.
(Did you mean the database/sql/driver driver.Rows interface[1]? sql.Rows is a struct not an interface.)
Just to be clear, you implemented a DB driver and then went to satisfy the driver interface? And this was after you already published it and would break backwards compatibility?
> especially as interfaces proliferate.
True. There will only be more interfaces over time. We'll want to keep them as small and descriptive as possible if we want the ecosystem to be sustainable.
edit: just to clarify: I don't like the idea "write more descriptive (over-verbose) method names" as solution for this problem.
And this is called the "adapter pattern" in Java. It's also very annoying to have to use it when you hit it.
You can easily make a wrapper type that simply masks the underlying Next() method with its own implementation.
type MyType struct {}
func (m *MyType) Next(i int) {
// do base next stuff
}
type ForSql struct {
*MyType
}
func (f ForSql) Next() bool {
// do sql-next stuff
}
and then using this type is trivial in-code: mt := &MyType{}
doSomeSqlThing(ForSql{mt})
Note that this new type retains all the methods of the original type, so it still implements all the interfaces it used to (unless they rely on the old Next signature).https://play.golang.org/p/t0gjJHjU7y
Edit: another variation on the same idea: https://play.golang.org/p/FqSFpMKQuv