I like that Go and Rust reexamined some of the underlying traditions of the C++/Java/C# approach to OOP rather than reflexively repeating them -- and while I think Go and Rust both, on a high level, took good (but very different) approaches, I think the one thing that Rust did right that would be better even with the rest of Go's approach than the way Go did it is explicit and detached declaration of interface implementations for data types.
So you're saying you'd prefer it if you had to explicitly tell Go that your type implements an interface? Something like this?
type Shape interface {
Area() int
}
type Square struct {
sideLen int
}
// Somehow denote that this function is implementing
// Shape's Area function
func (s Square) Shape.Area() int {
return sideLen * sideLen
}
Because, one of the things I like best about Go's interfaces is that you don't have to do that.
> So you're saying you'd prefer it if you had to explicitly tell Go that your type implements an interface?
I'd prefer that to having to avoid using the most natural names for methods to avoid implementing an unintended interface -- it seems to me that Go's approach in this area makes easy things easier and hard things harder.
Because conforming to the signatures necessary to implement an interface doesn't imply confirming to its semantics, so accidental interface "implementations" are a type-safety problem.
They're really not. You still have to have someone pass your type into something expecting an interface. It's no different than passing a string into something expecting a path when you pass it an html document... at some point the programmer needs to decide if passing the value into the method makes sense.
In the canonical example:
type Boat interface {
Launch()
}
func LaunchBoat(b Boat) {
// do some boat stuff
b.Launch()
}
type NuclearMissile struct{}
func (nm NuclearMissile) Launch() {
// launch nuclear missile
}
func main() {
rocket := NuclearMissile{}
LaunchBoat(rocket)
}
Sure, this compiles, but the code doesn't make any sense. Lots of things compile, that doesn't mean the code makes sense. At some point it's the programmer's responsibility to think a little.
> You still have to have someone pass your type into something expecting an interface.
Yes, that's generally the case with type-safety problems, even with the type-safety problem existing, it takes an actual programming error for it to become a problem -- and that is, indeed, the standard response of people saying type-safety isn't important (usually, though, its not a reason people would say something isn't a type-safety problem.) And its not completely invalid -- there is a reason that in a world dominated by static-typed languages with limiting type systems, dynamic languages like Ruby and Python that don't offer type safety but do offer a lot of flexibility that the type systems of C++/Java/etc. made, at best, cumbersome to acheive.
OTOH, if you are choosing a language with the extra ceremony involved in static typing, its kind of a big step back to not even get the level of safety with interfaces that you'd get with C#/Java, much less a more modern, expressive static type system.