And it's a relatively subtle language feature that does this, the way that any struct that implements a given interface automatically conforms to that interface without having to be declared. Which means you can declare an interface that foreign packages already conform to, and then freely use them. Which means that you can code freely with concrete structs to start with, and then trivially drop in interfaces to your code later, without having to go modify any other packages, which you may not even own.
I completely agree that on paper Java and Go look virtually identical. But the compounding effect of all those little differences makes them substantially different to work with. Good Go code does not look like good Java code. You'd never confuse them.
But you cannot do the reverse: you cannot make a type from a foreign package conform to your interface by adding new methods to it. This is because, with structural typing, it's not safe to add methods to types in other packages, since if packages B and C both were to add a conflicting method Foo to a type from package A, B and C could not be linked together. This is a major downside of structural typing for interfaces. Swift, for example, has the "extension" feature, and Java's design allows for it in principle, but it's fundamentally incompatible with Go's design.
I don't understand the idea that not having this feature somehow helps enforce dependency order either. Extension implementations of traits don't give you any more abstraction-breaking power than downcasting interface{} to a concrete type not defined in your package does. In fact, they're pretty much strictly less powerful.
I disagree. My best, fastest to compile code has always focused on just one type. You mention graphics programming: for 99.999% of the cases you want to pick a type. Usually, this will be float, and thus for SIMD a 4 or 8-vector of these, like https://github.com/aktau/threedee-simd/blob/master/include/t.... Despite the support of recent graphics cards for doubles, the fact is that they are usually quite a bit slower. Even when precision bound, there are usually tricks that will let one keep using floats (esp. wrt to Z-buffers).
I thought you could.
You don't add the methods directly to it, but you can easily embed the foreign type into a new type that confirms to the interface you want.
type FooWrapper struct {
Foo
}
func (fw FooWrapper) SomeFunc() {
...
}There are times when I love the structural typing aspects of golang (trivial dependency inversion) and there are times when I hate it (nontrivial renames), its one of many trade-offs you have to be prepared for in golang.
Except that it is very difficult to find out which struct implements what interface, you'd have to go look through the code. Not to mention there is always the possibility of accidentally implementing an interface. This has already caused real issues it seems (there was a blog post about it).
There already exists a solution for this issue, via typeclasses.
But golang doesn't have generics.
Take interfaces. In Java you might start with them. In Go - in the best case - they emerge, when it's time for them. Java has more mature tooling, but then, I cannot remember gathering runtime insights with Java quicker than with Go pprof[1].
Java is rock solid and more and more libraries are written in lightweight and clean way. Go has more momentum and also a growing number of curious users, who explore the language in creative ways[2].
[1] Google image search for "go pprof": https://goo.gl/6l7t1b
[2] Just discovered this amazing guy recently, https://github.com/fogleman/ln, https://github.com/fogleman/nes