Hacker News new | comments | show | ask | jobs | submit login
Mixins, Subclass Factories, and Method Advice in JavaScript (raganwald.com)
42 points by braythwayt 419 days ago | hide | past | web | 20 comments | favorite

This is probably a somewhat fringe sentiment, but reading this reminds me very much of http://codeofrob.com/entries/you-have-ruined-javascript.html (I was making very similar comments while reading this)

I'll readily admit I'm biased against OOP; I much prefer functional approaches. When I write Javascript, it tends to be pretty functional, with minimal OOP conventions.

But that said...all the problems this addresses are self-inflicted problems. The very start of the article even says as much, "Mixins solve a very common problem in class-centric OOP" - that is, "these problems are only problems because you want to write Javascript in class-centric OOP", something it wasn't really designed for (and the constant attempts have led to Ecmascript 7 and the 'class' keyword, which I find myself shaking my head at; again, see prior link, at trying to make Javascript feel 'enterprisey').

Find another way to go about it maybe? The subclassFactory example he gives...if I saw that in a code base I'd want to punch someone. Because without the writeup he gives, I'd be staring at it, and the functions it calls, for a good 20 minutes before figuring out what it's doing. And all it's doing is trying to shoehorn a specific paradigm into a language not written for it. I mean, you can do it, sure, but -why-? I don't really like Javascript but at least I feel pretty productive in it; why would I make it harder on myself, and everyone who reads my code after me, by trying to make it something it isn't?

Perhaps the author ought to spend some time reading a book like JavaScript Allongé and learn how Functional Programming in JavaScript is done ;-)


Sarcasm aside, I know raganwald (you?) can approach things functionally. :P My comment isn't to imply he can't (nor that I'm particularly good at it), nor to imply anything about his choices when writing code (as I said, he correctly notes that this is an issue when trying to write class-centric OOP in Javascript; this says nothing about his views on whether class-centric OOP in Javascript is a good idea or not). And, certainly, come ES6, mixins get some language help with Object.assign.

My point is simply that if in ES5 you have to fight this much with the language to try and shoehorn it into a particular paradigm, maybe you've picked the wrong paradigm for that language. And the fact so many people try, and so many authors have written ways to try and shoehorn that paradigm into the language (as it stands at ES5), tells me that it -really- is probably not the best choice.

And the insistence in doing so seems like a misplaced "make it behave like Java" that brought to mind that URL I linked.

That's not to say thinking about it isn't itself a worthwhile endeavor. That's not to say that seeing that it can be done in Javascript isn't a point in Javascript's favor. That's not to say there isn't a demand by people for the language to behave this way, and that others understandably try to meet that demand. But it is to say that it's solving a problem that is self-inflicted, by dint of choosing to use classical inheritance in a language that was designed to support prototypal inheritance.

It’s a question of taste.

To me, hierarchies of classes are not very JavaScript, but mixins written as decorators are very JavaScript.

To me, overriding functions and calling `super` is not very JavaScript, but writing function combinators like `before` and `after` is very JavaScript.

To me, JavaScript is about composing bunches of single-responsibility things, not writing big things.

So to my taste, mixins and decorators are in a deep way, strongly related to functional programming, while the sugar for stuff like classes and special syntax for getters and setters is not.

That's fair, and I'd agree that mixins and decorators can be more closely related to FP than I initially took them for.

I just tend to keep my objects as, basically, structs, and functions bound outside of them, rather than treating them as objects, so questions of composability in such a manner don't come up. Rather than have to write a lot of abstracted out code to support mixins, and then know what assumptions a mixin has about the object choosing to mix it in, there are instead just functions; you want them then reference them, and what they take is spelled out (somewhat more) clearly in the function header, if you can pass in the right arguments, the function can be reused. If you want a set of functions that all work together, then composition, sharing state, etc, falls on you, rather than being implicit in assumptions the mixin and mixing class may make about each other. As you say, a question of taste (especially as to what steps you take to avoid those assumptions).

But that said, I've done similar things in merging two objects prior to serializing them out across a REST endpoint. So there it was less a design consideration of composable function containers, and more one of data transformation (not that they're separate beasts; functions as data and all that), but at the same time a lot of the complexities were avoided.

Great write up, and neat ideas. One of my biggest hurdles on learning Javascript so far is that because definitions are so flexible, its very difficult to pick up a code base with an unfamiliar structure. Mixins in particular spread code between files, and the mixin itself is often hidden, or not obvious. At least in Java, I know I can look at extends, and trace it from there.

The decorator pattern seems like it would be pretty obvious. But its yet another non standard way to create objects. If I saw without explanation, I would be at a loss on how it works, or even what it does. At least method overriding is consistent when it is baked into a language. But having to learn a new mixin/inheritance/definition pattern for each codebase has given me serious troubles recently.

  > At least method overriding is consistent when it is baked into a language
Right there you have one of the two great families of programming. You like things like Python, where there is only one obvious way to do anything, and if it isn’t obvious, you just don’t do it. These ideas are from the other family, where you have a number of small but powerful ideas that you can combine in various ways.

The ones that solve problems and have great timing and get some marketing oomph establish community traction, the rest fade away. This is the UNIX and Lisp tradition.

I can’t tell you whether one is better than the other. I can tell you that the first thing is IBM. And opinionated frameworks. And benevolent dictators. The second thing is startups. And libraries. And tinkerers. There’s no shame in preferring one to the other. Both have produced great things.

I look forward to the day when the rest fades away from Javascript. Right now it is the wild west in terms of pattern usage, especially when it comes to implementing "private" variables with some scope tricks that result in unreadable code.

I like what raganwald writes but let's get real here. People asked for the class keyword because it made classes easier to write AND read. OOP with prototypes is dreadfull, from a "clean code" perspective.

Javascript should get the same perks for mixins, because going back to "builders" is going back to everybody writing his own flavor of the same stuff and doesn't make things readable anymore.

Is there a mixins proposal for ES7 ?

a simple thing would be to allow multiple inheritance :

    class Foo extends Bar,Baz {}
just like Python

I think the Python way is the simplest one.

You know, given the sheer amount of JS that has been written successfully in the last ten years, I think it might be worth asking: is it really needed to continue mudballing that type of stuff onto the language?

Especially with mixins and things, it's really easy to add so much magic to the code that getting up to speed on what something is doing becomes prohibitive. It's really great for flavor-of-the-week frameworks, but long term maintenance can become a nightmare and proper performance tuning difficult.

Then again, maybe we don't care about maintenance and performance anymore.

> You know, given the sheer amount of JS that has been written successfully in the last ten years, I think it might be worth asking: is it really needed to continue mudballing that type of stuff onto the language?

That's a good question. If it helps write a specific pattern and make it more readable I think it's worth it.

People are going to write these stuff anyway, why not help making things more readable for anybody else ? it's not going to change the nature of javascript, I'd argue that things like proxies or decorators are far more questionable than multiple inheritance, yet they made/are making it to the spec.

Nobody can deny Python code looks usually clean and mostly readable. Nobody can deny that Javascript code is often unreadable because ES3/5 developers didn't have the syntax to convey specific ideas in a eloquent way(thus all the prototype plumbing, module pattern and co that made js code look like brainfuck,don't even get me started on ninja coding).

Javascript is not readable to you because you're attempting to apply OO patterns to it.

Javascript is not an OO language, it doesn't work like that.

It is an incredibly powerful and elegant language, please take the time to learn how it works and appreciate its beauty. Then by all means make suggestions about how it should be changed. But only then, please.

Not all languages would be improved by being "more like Python".

> Javascript is not an OO language, it doesn't work like that.

What ? it certainly is today with the "class" syntax. Or it is like saying neither Ruby or Python are object oriented.

> elegant language,

Elegance is in the eye of the beholder

Minor point of order...Ruby is OO because it very much follows the Smalltalk-style message-as-function-invocation pattern.

Javascript (at least before ES6) is perhaps too minimal in its language affordances to qualify for "true" OO status.

there's a lot of people who objected to adding "class" syntax to Javascript purely for this reason. Javascript objects are not the same things as Python (or Smalltalk) objects, they don't work the same way and were never intended to.

There is a good case to be made that Smalltalk-type OO with multiple inheritance (like Python) is a bad thing. Javascript's type of OO is a good way of avoiding that bad thing.

I agree that elegance is purely subjective, and if you choose not to find javascript elegant because it lacks a certain "python-ness" then that's entirely your decision. However I would encourage you to expand your horizons a bit and stretch your understanding a little more.

  > Is there a mixins proposal for ES7 ?
What’s more likely to make it to ES.whenever:

1. “Here’s a mixins proposal, it would make the language better.”

2. “People are writing mixins and like them, but some syntactic sugar would helps standardize the way they’re written. Here’s a proposal to do that.”


> OOP with prototypes is dreadfull, from a "clean code" perspective.

> I think the Python way is the simplest one.

FYI, Python actually does use prototypical inheritance under the hood. The difference between Python and ES5 is that Python uses the "class" keyword in such a way that you don't actually need to know about prototypical inheritance in order to use Python unless you're doing some really funky work with Python's metaclasses.

I believe a form of mixins has already made it into TypeScript:


Still would prefer them to be more built-in.

Actually no, you still have to write a mixin builder function in your code. Typescript just supports declaring mixin types, it doesn't do the actual implementation.

oh god no please not multiple inheritance.

Javascript objects are composable at run-time: you can build your object out of whatever behaviours you need. They don't need multiple inheritance.

Can we stop trying to make Javascript an OO language please?

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact