On Mon, Mar 10, 2014 at 6:50 PM, Ian Kelly <ian.g.ke...@gmail.com> wrote: > The author points out that nested structures can be made optional by > including a pointer to the structure instead of the structure itself. > Again you can do the exact same thing in C++; in OOP this is usually > described as a "has-a" relationship. Most languages don't support the > syntactic sugar that makes this look almost identical to inheritance > in Go, but that's all it is.
Composition versus single inheritance versus multiple inheritance. Where's the line drawn? In Python, it's easy to tell one from another. Composition hides everything behind another dot level; single and multiple inheritance use the MRO (with MI handled by "super" sometimes pointing you to a peer). But compare this: class command { void create(string name) {.......} void process(...) {...} } class hook { void create(string name) {.......} void inputhook(...) {...} } class timer { inherit command; inherit hook; void create(string name) {::create(name); .....} } This is part of the class hierarchy of Gypsum, implemented in Pike. It looks like multiple inheritance, and it mostly works that way. Given an instance of timer, you can call process() on it as a command, or inputhook() as a hook. The create() function (which is like Python's __init__) defers to its parents using a C++ syntax form with the leading double colon - but without C++'s ambiguity error. (The specific case of the constructor is different in C++, but any other duplicate method name would be a compile-time error. In Pike, the expression "::create" actually returns an array of functions, in the order of the inherits; and calling an array of functions calls each function in turn with the same args.) So this definitely acts like MI. And the syntax is almost the same as SI, in that removing the "inherit hook;" statement will have this function beautifully as straight-forward single inheritance. But consider this: class foo { inherit Stdio.File : file1; inherit Stdio.File : file2; void readwrite() { //Assumes both files were opened by other methods file1::write(file2::read()); } } So multiple inheritance is really just composition in disguise. (Actually, this last form is stylistically discouraged. It's normally much clearer to use a more classic form of composition, which works the same way Python's does. But it does work, and there are uses for it.) I think it's only the theory purists who really care strongly about the differences between all the various terms. There's an implication to inheritance (Liskov Substitution Principle) that composition doesn't have, but *every* (bar none!) implementation of Multiple Inheritance I've ever seen is either horribly horribly sucky, or ends up creating some edge cases that make LSP a little odd. (Or both.) So don't sweat the details. Practicality beats purity. I think C++'s MI implementation is more on the pure side and less on the practical... and I've never used it in production code. Python's MI is fairly practical, but requires that every class in the hierarchy be able to cope with MI, and has odd edge cases with "might be the last in the tree". Pike's MI has oddities with external "reaching in" to something, so sometimes I need to write explicit dummy methods, or carefully avoid name collisions; definitely practical, and quite useful. Java's MI simply doesn't exist (that's perfectly pure!), although implementing interfaces can do a lot of it; but then you end up duplicating piles of code (on the other hand, that's nothing new in Java code). I don't remember what other languages I've tried MI in, but most of them tended toward the "pure" and were impractical enough to avoid using. ChrisA -- https://mail.python.org/mailman/listinfo/python-list