I agree that you have to draw the line somewhere, but I believe the is-a/has-a dichotomy more accurately separates the different modes of thinking. To me the structure of a Go program is completely indistinguishable from one in C++ (precisely because of the lack of inheritance). When I look at the design of a C++ program (or say Obj-C), its all about class hierarchies. The docs are all about the class diagrams, step 1 of most those programs is usually "subclass ___". It immediately drops you into that view of the world, and I believe that with that view comes the guiding hand of your program's design.
Compare that to Go, which focuses on the traits of objects instead of their incidental ancestry. In go you'd define a function or method applying to an abstract interface that has certain properties. For example, I would say "give me an object that has a show method", not "give me something inheriting from Printable". This is completely analogous to the very abstract typeclass-style programming you do in Haskell ("give me something that derives Show"). Haskell object architecture is all about defining an abstract typeclass and reasoning about what you can do given these existing methods. You then supply an implementation that fits the type class definition, exactly the same abstract analysis of fundamental properties divorced from their specific owners as inheritance-less interface/protocol programming in a language like Go.
Again, there is quite literally no difference in "binding" a function to an object through the dot syntax vs through type. If in haskell you say the meow function applies to the Cat data type its not any different than having a meow() method on a Cat in C++, neither can call that on anything else, its quite bound.
Comments
I agree that you have to draw the line somewhere, but I believe the is-a/has-a dichotomy more accurately separates the different modes of thinking. To me the structure of a Go program is completely indistinguishable from one in C++ (precisely because of the lack of inheritance). When I look at the design of a C++ program (or say Obj-C), its all about class hierarchies. The docs are all about the class diagrams, step 1 of most those programs is usually "subclass ___". It immediately drops you into that view of the world, and I believe that with that view comes the guiding hand of your program's design.
Compare that to Go, which focuses on the traits of objects instead of their incidental ancestry. In go you'd define a function or method applying to an abstract interface that has certain properties. For example, I would say "give me an object that has a show method", not "give me something inheriting from Printable". This is completely analogous to the very abstract typeclass-style programming you do in Haskell ("give me something that derives Show"). Haskell object architecture is all about defining an abstract typeclass and reasoning about what you can do given these existing methods. You then supply an implementation that fits the type class definition, exactly the same abstract analysis of fundamental properties divorced from their specific owners as inheritance-less interface/protocol programming in a language like Go.
Again, there is quite literally no difference in "binding" a function to an object through the dot syntax vs through type. If in haskell you say the meow function applies to the Cat data type its not any different than having a meow() method on a Cat in C++, neither can call that on anything else, its quite bound.