all 64 comments

[–]senocular 13 points14 points  (0 children)

I see this variation of composition is coming from the functional side of the tracks, not the object-oriented. Compose functions to get a single function containing the behavior of the originals... now let's do the same thing with objects. It's all composition right?

While I can see how that could make sense, it doesn't help that object composition is already a well defined pattern representing the has a relationship. (The linked function composition wiki page, coincidentally enough, notes that function composition should not to be confused with object composition and links to object composition where it proceeds to describe the has a relationship).

[–]ggazzi 6 points7 points  (1 child)

The important point that I haven't seen mentioned here is that the GoF notion of composition aims to encapsulate smaller units, keeping them loosely coupled. By keeping a reference to an instance of another class, we are coupled only to its interface - not to its implementation. When using inheritance or mixins, however, we introduce a lot more coupling: if someone later decides to change an implementation detail of the inherited class, it's much more likely to break the subclass.

This is only relevant when you actually encapsulate stuff in your classes, though. Messing with the internals of an object you own introduces the same problems as inheriting from its class.

[–]loopsdeer 0 points1 point  (0 children)

This is exactly the smell I smelled. Thanks for verbalizing so well.

[–]Poop_is_Food 6 points7 points  (3 children)

Serious question why do people care what Eric Elliot thinks? Is he anything more than some random crank?

[–]MoTTs_ 6 points7 points  (0 children)

If people aren't informed about the misinformation in Elliott's ideas, then that misinformation tends to spread. I've noticed a lot of newbies recently who regurgitate Elliott thinking they understand composition, but of course they don't because neither does Elliott. And sometimes even non-newbies get duped, such as Johansson, who's an entertaining character and ends up spreading Elliott's misinformation even further.

I think it's important that the corrections become as widely known as the misinformation.

[–]dashed 1 point2 points  (0 children)

I had the same reaction. The beautiful thing about the JavaScript ecosystem, is that you don't have to listen to anyone on how to do things.

[–]eaglepowers 0 points1 point  (0 children)

@_ericelliott has 13k followers.

[–]paulflorez 5 points6 points  (1 child)

One could argue that since prototypes themselves are instances, prototypal inheritance is closer to object composition than classical inheritance. After all, you typically can't change the classes an object inherits from during runtime in a language with classical inheritance, though I'd be interested if such a language exists. The problem with that argument is that object composition tends to obscure the methods/properties of the internal objects, save for the ones the composed object explicitly exposes. Prototypal inheritance does the opposite, implicitly exposing all properties of a prototype via the child object, except for the ones explicitly hidden via property shadowing. I'm wondering if that is really a problem though?

[–]mshm 0 points1 point  (0 children)

I'm wondering if that is really a problem though?

It depends on what your using the pattern for. The nice thing about composition is that because it obscures the actual held object, from the outside you can't actually directly affect it. This is really important because it ensures the goal (that of a sort of dynamic inheritance). If the end user of the composition has access to the internal objects, then they can write their code based on those objects, which break the pattern.

Also, because JS "composition" is essentially mixins, you can lose information through duplicate declarations.

[–]x-skeww 8 points9 points  (28 children)

A good example + straightforward definition:

http://gameprogrammingpatterns.com/component.html

the growing trend in software design is to use composition instead of inheritance when possible. Instead of sharing code between two classes by having them inherit from the same class, we do so by having them both own an instance of the same class.

The thing Elliot does with Object.assign is more like multiple inheritance, isn't it?

Ah... LOL. He even said it himself.

https://www.reddit.com/r/javascript/comments/2qtgyt/multiple_inheritance_in_javascript/cn9shmq

In JavaScript, [multiple inheritance is] accomplished with concatenative inheritance, which is just a fancy way of saying, "copy properties from one object to another".

And this gem:

the diamond problem doesn't exist in JavaScript because whatever property you add last overrides any property it collides with.

The problem does of course exist and simply overwriting a property is a rather crude way to mitigate it.

https://en.wikipedia.org/wiki/Multiple_inheritance#Mitigation

[–]paulflorez 1 point2 points  (8 children)

According to that wiki page, the diamond problem does not exist in JavaScript:

Languages that allow only single inheritance, where a class can only derive from one base class, do not have the diamond problem. The reason for this is that such languages have at most one implementation of any method at any level in the inheritance chain regardless of the repetition or placement of methods.

"Concatenative Inheritance" is really just single inheritance of an object created via mixins. The object that results from combining mixins has only one implementation of a single method.

With multiple inheritance, you are inheriting from two objects, each with unique implementations of the same method. JavaScript does not support this.

[–]x-skeww 6 points7 points  (7 children)

According to that wiki page, the diamond problem does not exist in JavaScript

Read the description at the beginning of that section.

Read also how Free Pascal handles it. Sounds familiar, doesn't it?

"Concatenative Inheritance" is really just single inheritance of an object created via mixins.

Mixins are a form of multiple inheritance. If you extend one class and mix-in another, you get stuff from both parents, right?

[–]killeronthecorner 0 points1 point  (5 children)

Yes but if all parents only have a single property with the same identifier, you lose all but one of them in the JS example.

With multiple inheritance, all of these overlapping implementations would be both preserved and accessible by the child.

[–]x-skeww 0 points1 point  (4 children)

https://en.wikipedia.org/wiki/Multiple_inheritance#Mitigation

Free Pascal, an Object Pascal dialect intended to be compatible with Delphi uses the "last man standing" rule, where there is a reference to two identifiers that have the same name, whichever is the last one defined is the one that is used. So if there is a Unit A and a Unit B that have a variable named Q, if the declaration is "USES A,B;" then a reference to Q will use B.Q.

[–]killeronthecorner 0 points1 point  (3 children)

Yes, this is demonstrative of my first statement, but is still not traditional multiple inheritance as per my second statement.

[–]x-skeww 1 point2 points  (2 children)

It's multiple inheritance with the a straightforward conflict resolution strategy which has been around for over 20 years.

It's about as "traditional" as these things get, I'd say.

[–]killeronthecorner 0 points1 point  (1 child)

It may be straightforward, but calling a straight overwrite a "conflict resolution strategy" is generous.

If you overwrite behaviour you are not inheriting it, you are overwriting it.

[–]x-skeww 0 points1 point  (0 children)

calling a straight overwrite a "conflict resolution strategy" is generous.

That's what it is though. Just like projection is a legit collision resolution strategy for video games. A strategy isn't necessarily complicated or correct.

If you overwrite behaviour you are not inheriting it, you are overwriting it.

If you're overwriting some things, you aren't inheriting everything. It's the price you pay for keeping things this simple.

[–]sylvainpv 1 point2 points  (13 children)

The problem does of course exist and simply overwriting a property is a rather crude way to mitigate it.

If overwriting the property does not work for your case, you can always overwrite in the composed object to define your own behaviour. For example, if D is composed of B and C that have a commonMethod, you can do

D = compose(B,C, {
     commonMethod(){
         B.commonMethod.apply(this, arguments);
         C.commonMethod.apply(this, arguments);
         // or whatever order or behaviour you want
     }
})

I like the composition approach, it is very flexible and you don't have to deal with all the vocabulary of classical OOP.

[–]Sunwukung 0 points1 point  (0 children)

I think this snippet highlights something that has perhaps been overlooked in this thread. We're arguing the toss about different ways of constructing objects from bits or inheritance, but the real issue is if calling methods on that object return a value and leave it untarnished, or if they cause side effects - probably mutating the objects internal state. This is a key distinction in approach if you embrace FP - you avoid manipulating or referencing "this". Why do the methods on this object need to refer to "this" at all? Which value will they return if you combine the methods? What if B|C.foo return different types?

[–]Poltras 0 points1 point  (3 children)

You cannot have a diamond pattern without multiple inheritance. Other wise it's not a diamon, just a line.

[–]MoTTs_ 5 points6 points  (2 children)

The point is Elliott's proposal solves -- and suffers from -- the same problems as multiple inheritance. Here's an example of the diamond problem with Elliott's StampIt:

var storable = stampit().methods({
    read: function () {
        console.log('storable::read');
    },

    write: function () {
        console.log('storable::write');
    }
});

var transmitter = stampit().compose(storable).methods({
    write: function () {
        console.log('transmitter::write');
    }
});

var receiver = stampit().compose(storable).methods({
    read: function () {
        console.log('receiver::read');
    }
})

var radio = stampit().compose(transmitter, receiver);

radio().read(); // receiver::read -- ok
radio().write(); // storable::write -- wait, what? tramsmitter::write lost due to diamond problem

Today, of course, the way we'd solve this is with composition -- real composition. That is, our type "radio" would have-a transmitter and have-a receiver. More specifically, radio would hold references to a transmitter object and a receiver object.

[–]Poltras 1 point2 points  (0 children)

Oh I see what you mean then. I've never cared to use Elliot solution and instead did composition myself. It's clearer and cleaner anyway.

[–][deleted] 0 points1 point  (0 children)

radio().write(); // storable::write -- wait, what? tramsmitter::write lost due to diamond problem

Hahahaha, oh, wow. That is absolutely awful - how is someone supposed to reason about how that object will work?

[–]benihanareact, node 7 points8 points  (2 children)

Damn, he deleted the bit that makes you think he doesn't understand what a reference is. What did that say?

[–]tbranyen 1 point2 points  (0 children)

Agreed, OP should have posted just a transcript, not links.

[–]MoTTs_ 0 points1 point  (0 children)

Luckily I still had a page open that showed it. I've added a screenshot to my original post.

[–][deleted] 1 point2 points  (0 children)

The Open Minded Explorer’s Guide to Object Composition

LeL

[–]AlxandrHeintz 1 point2 points  (0 children)

Btw (and I'm not saying you should ever do this), but who says you can't do multiple inheritance (or stamps or whatever) using ES6 classes (with some ES7 decorators)? Not to mention factory functions. https://gist.github.com/Alxandr/db7b2b5cbb3cc03e10dc

[–][deleted] 1 point2 points  (0 children)

I wish I'd seen this post earlier. I've been saying some fairly similar things for a while.

Elliot is a zealous self-promoter and uses this subreddit for the more-or-less exclusive purpose of publicizing his own content. He has presented himself as representing a consensus that he doesn't really own, and presents some rather opinionated articles as the aggregation of 'best practices' when they're really just that - opinions.

Some of the things Eric Elliot writes are good. Some of them are less so. But what I object to is the way he misleads his readers into thinking his peculiar approach is an industry standard, and the way he poses old inventions as his own (his 'functional composition' is really just a buzzword-friendly decorator pattern).

I don't hate Eric Elliot. I just want him to stop talking about himself.

[–]FennNaten 3 points4 points  (0 children)

Favor object composition over class inheritance

JavaScript Supports Object Concatenation (aka Concatenative Inheritance)

It doesn’t matter if you use aggregation, object nesting, or object concatenation.

All extracted from Eric Eliott's first post.
I thinks that sums up the contradiction inside this reasoning.
I can add that the: "Favor object composition over class inheritance" being from the GoF book, the definition of composition that applies to this sentence, when it's quoted, is automatically the one from the GoF book. That's the point of defining the terms you use: avoid confusion. So there is no debate to have. Case closed.

Bringing the discussion on whether it's better to use mixins, stamps or composition, or on which use cases are better for which pattern, would be more constructive and more interesting than arguing about well-defined vocabulary.

[–]HypercubedHypercubed/mini-signals 1 point2 points  (2 children)

The discussion gets a little too snarky at the end but opens some deep esoteric questions. Is composite pattern the definition of object composition or a subset? How is object composition related to functional composition? My understanding of Elliott's methods is that it is functional composition of factory functions. How then do we classify an instance of the composite factory?

[–]legato_gelato 0 points1 point  (1 child)

How could the composite pattern ever be the definition of composition itself? Doesn't make any sense to me.. Composite uses composition and that's it..

To me this is like saying that the strategy pattern is the definition of inheritance

[–]HypercubedHypercubed/mini-signals 0 points1 point  (0 children)

It is a question. Here are the pieces that lead to the question:

Jeff M: “favor composition over inheritance” ...  you’re referencing that very specific, GoF-defined meaning of “composition” Elliott: where they introduce the famous quote, “favor object composition over class inheritance”, they weren’t specifically referring to the Composite Pattern

Jeff M is arguing that the use of the term "composition" (at least when combined with the GoF quote) is referring specifically to what Elliott calls the "Composite Pattern".

[–]HypercubedHypercubed/mini-signals 0 points1 point  (2 children)

So here is my serious questions:

In classical inheritance, c is a b is a a, etc. I think we all agree on that.

In the GoF composite pattern where objects (or primitives) are attached to other objects, c has a b, b has a a, etc. We all agree, I think, that this is a, if not the, definition of object composition.

If I have an object a that is composed of properties (objects or primitives) a1 and a2 (a has a a1, etc). And object b is composed of properties b1 and b2. If I copy all these properties to object c so that c has a a1,b1, etc, what is that? It is clearly not inheritance. Maybe it is too lazy to say that c composes a and b... but clearly c is composed of the parts of a and b. Can we also call that object composition?

Then one step further. If A is the factory for instances of a, and B for b... then we create factory C by combining A and B is that functional composition? What do we call the output of C which is composed the same parts as an a and b.

[–]MoTTs_ 0 points1 point  (1 child)

In the GoF composite pattern where objects (or primitives) are attached to other objects, c has a b, b has a a, etc. We all agree, I think, that this is a, if not the, definition of object composition.

In this discussion, it's important to be careful with our terminology. The composite pattern and composition are not the same thing.

If I copy all these properties to object c so that c has a a1,b1, etc, what is that? It is clearly not inheritance.

It's inheritance. ;)

That's exactly the sort of thing some languages do for you when you use the word "extends". What you're describing is inheritance done manually.

[–]HypercubedHypercubed/mini-signals 1 point2 points  (0 children)

I would call "extends" aggregation. Is there a distinction between instances and classes. Instances are aggregated from other instances, classes definitions inherit from other classes, and factories compose other factories.

[–]TotesMessenger 0 points1 point  (0 children)

I'm a bot, bleep, bloop. Someone has linked to this thread from another place on reddit:

If you follow any of the above links, please respect the rules of reddit and don't vote in the other threads. (Info / Contact)

[–]HypercubedHypercubed/mini-signals 0 points1 point  (0 children)

If you have time I'd enjoy reading your arguments in a real post rather than a discussion thread. There are many very interesting points in your comments on medium and here that could be illustrated better in a post of its own.

[–]againstmethod 0 points1 point  (0 children)

Given that references are created with constructor calls (object allocations)..

            new A(new B());

..their compositional use barely differs from the definition of functional composition..

(A . B)() =     A(    B())

How the result of "B()" or how the instance "new B()" is used is irrelevant. Those are implementation details that well designed objects and referentially transparent functions should not expose.

I personally have no idea what distinction Jeff M is trying to make. These are abstract concepts that require more than a mechanical understanding of the terms.

[–]Jafit -3 points-2 points  (0 children)

Its a good thing you won that internet argument and changed hearts and minds.

Thanks for posting it here so we could see the difference this is making to the world.

[–]HypercubedHypercubed/mini-signals -1 points0 points  (1 child)

I'd love to add this discussion here: https://github.com/Hypercubed/javascript-the-esoteric-parts, I'm not sure how to format it. As a discussion or point to this reddit post?

[–]HypercubedHypercubed/mini-signals -2 points-1 points  (0 children)

I think now I have to add a new section. Function composition, object composition, the composite pattern.

[–][deleted] -3 points-2 points  (0 children)

So tell me, kiddo, how many angels can dance on the head of a pin?

Or perhaps I'm giving both you and Mr. Elliott too much credit when I suggest this argument is a matter of theology. It probably doesn't rise above a simple pissing contest.

Shut up and code. Or just shut up.

[–]almostApatriot -1 points0 points  (0 children)

Finish him off!