Does anybody know how Go manages to call the given function of the matching interface when it gets only a pointer to the struct? Like here, where label and button are otherwise unrelated structs but both have the same Paint function:
for _, painter := range []Painter{label, listBox, button1, button2} {
painter.Paint()
}
In C++, where inheritance is used, the virtual function pointer tables are maintained and the inherited class will have the function at the same index which makes calls of virtual functions slower than normal calls but the cost is still just an indexing of the table. However when there is no inheritance specification, the indexes can't be maintained, I presume. The easy solution is that calls are resolved using some string fingerprint lookup but that would make such calls really slow (compared to the C++).
It doesn't get a pointer to the struct, it gets an object that implements whatever interface. At least that's the story from the type system perspective.
Given that, it seems easy enough to just pass a {pointer, vtable} value.
In C++ (if I understand correctly) each object/class has one vtable. In Go, it seems that each type has as many vtables as are needed for the contexts it's called in.
See also type classes in haskell.
(this is all guessing. Someone please call me out if I'm wrong)
"Unique" is a fair description of Go's approach to OO: The ideas it is based around may not be totally original, but the implementation is different from any language in common use.
I don't think it should be baked into the language. With a good macro or compiler plugin system, you can implement composition as a library. This is already the case for languages like Haskell, Racket, and Scala.
The more general ideas that underpin a composition implementation are the abilities to access class/interface metadata at compile time and to generate code programmatically at compile time.
That was always a problem for Tcl: the language is flexible enough that you can write an OO system in Tcl, or via its C API, but with several around, and non distributed with Tcl, you couldn't really count on any of them, or worse, you might find two bits of code depending on two different systems. I think they've finally cleaned this up some, but I view it as a mistake.
Every project has friction between members, disagreements,
conflicts over style and philosophy. These social problems
are counter-acted by the fact that no large project can be
accomplished otherwise. "We must all hang together, or we will
all hang separately." But the expressiveness of Lisp makes
this countervailing force much weaker; one can always start
one's own project. Thus, individual hackers decide that the
trouble isn't worth it. So they either quit the project, or
don't join the project to begin with. This is the Lisp Curse.
I like the idea of having a standard object system in the language, don't get me wrong. But having a standard object system and baking compositional inheritance as a core primitive of the language are two different things. The latter isn't a terrible thing at all. I just believe that there are more general language features that subsume it.
I think there are some obvious mistakes in it: 1) The NewXXX() function should return a pointer by Go idioms. But they return the value in this article. 2) For methods on IntSet type, it says the receiver should be pointer instead of value. "If we used values, these would be copied and any changes applied lost." Actually, since the data field is a reference, using value as receiver can change the content of the map.
Then how do they do it?