11 ms·
JS Objects: Inherited a Mess
- DonPellegrino 14y agoI wrote this snippet of code to explain the concept of function/hashmap/object/class to javascript beginners. http://jsfiddle.net/AXTdj/ http://jsfiddle.net/AXTdj/
- yuchi 14y agoWe're probably going to see some declination of the parasitic inheritance in the next parts, none-the-less this article has been a good read. You don't find a lot of real JS article these days.
- _getify 14y agoI will not be directly addressing "parasitic inheritance" as I never saw it to be a terribly useful pattern, honestly. I see it very rarely used and even more rarely referenced by that name. The point I'd make about it here, though, which is generically reflected in today's part 2 article, is that it's a fine pattern in and of itself, but the reason I think it's a "distraction" is that it actually moves away from the [[Prototype]] chain entirely. You can use it as a bespoke pattern for combining two objects, but it's a mistake/confusion to think this has anything to do with JS's underlying delegation mechanism. The same point is made about mixins, and polymorphism (which also requires implicit mixins).
- yuchi 14y agoI have to admin part 2 perfectly sums my ideas about JS and classical OOP inheritance. Looking forward part3 and its "solution".
- lispm 14y agoIt's prototypical OO. Don't swim against the current. Swim with the current. It's not inheritance - it is delegation. It's just like in several other object-oriented languages: Self, NewtonScript ( http://waltersmith.us/newton/OOPSLA95.pdf http://waltersmith.us/newton/OOPSLA95.pdf ), Object Lisp ( http://lispm.dyndns.org/docs/ObjectLisp-Manual.pdf http://lispm.dyndns.org/docs/ObjectLisp-Manual.pdf ), MacFrames, ... This is a classic example that it is difficult to unlearn a concept. Q: how long does it take to learn prototype-based OO? A: a day is sufficient. If you know class-based OO you'll need three days.
- smosher 14y agoI have to plug Io: http://iolanguage.org/ http://iolanguage.org/
- epidemian 14y agoAnd don't forget its cuter descendant, Ioke: http://ioke.org/ http://ioke.org/
- smosher 14y agoOf course. I wish I could use Ioke, but JVM/CLR just aren't in the cards for me for the foreseeable. On the subject of derivatives, I think Oia is at a sweet-spot, being JS-hosted at ~1-2kSLoC (1/5th-1/10th that of Io): https://github.com/stevedekorte/oia https://github.com/stevedekorte/oia
- thezilch 14y agoI think that's the argument -- naming is hard. Most JS libraries want to expose a class-based model -- call it class(es) -- and often to appeal to the non-prototypical crowd. Tutorials and documentation are rife with Java'esque examples. Instead, said JS libraries should possibly be exposing said `new Class()` as `new Delegate()`.
- protomyth 14y ago"often to appeal to the non-prototypical crowd" Isn't that the sad part? Its like Java / C++ is it for a lot of people and every other language has to fit that pattern.
- coldtea 14y agoOr it might be that the prototype thing never really caught on and people want something more class like. Why assume prototypes are better or that people should adapt to whatever (potentially BS) way a language offers for organizing code, instead of the other way around (languages should adapt to the way people want to use them).
- mcmire 14y agoThe real mess is how in ES6 they (the ES6 WG I mean) are furthering the illusion that JS supports classical OO, which is completely crazy. They should be going the other direction (and I think /be wanted to) but they steered away from that and seem to think that mixing syntaxes and thus concepts is the right move. I would imagine this article series will talk that eventually, though, kind of hard not to.
- deleted 14y ago[deleted]
- ax 14y agoI think BE is a fan of the max-min class proposal... At any rate, naming aside, ES6 classes are simple syntactic sugar for a very common pattern in JS development today. It makes sense to provide a syntactic sugar in this case that makes developer intention clear and reduces boilerplate. TypeScript has (I believe) a mostly compatible implementation of these classes if you want to try them out in today's runtimes.
- coldtea 14y ago>They should be going the other direction Why? If the people want a language changed, most abuse the current prototype system to be more classic class like (including top notch programmers), and there is a demand for it, why not add a proper class syntax, even as a sugar for the common workaround? It's like saying people must adapt to the idiomatic ways of a language without offering any proof that those are better (and no, random qualities like "more flexible" is not necessarily better in actual use). I don't think we should worship "idiomatic" ways of each language. For example, tons of Beans, XML, and boilerplate was the idiomatic Java way, but then projects came along and showed it could be done better (e.g Play). Using every feature under the sun and abusing templates is kind of an idiomatic C++ way, but people are arguing successfully for merely using C++ only as a C with classes and some minimal features.
- jarek-foksa 14y agoJavaScript was a pseudo-classical language from the beginning. JS constructors were and still are the core language feature that clearly tries to mimic classes from Java. I agree that's it's awful, but it can't be depracated or removed from the language because there is so much code relying on it. Evolving JS into language with minimal dynamic classes such as Python or Ruby should be easy as all interfaces are already "classical", you just need to add some syntactic sugar. This approach was already proved to work by CoffeeScript and TypeScript. I can't imagine how JS could be evolved into clean prototypal language such Io without breaking backwards compatibility. There is no hope for JavaScript to become elegant prototypal language because of the design mistakes that were done in the past. All that TC39 / ECMAScript.next committee can do is put even more lipstick on a pig. http://this-plt-life.tumblr.com/post/36425234595/when-somebody-tries-to-explain-javascripts-prototype http://this-plt-life.tumblr.com/post/36425234595/when-somebo... http://this-plt-life.tumblr.com/post/41438931672/when-somebody-says-js-has-a-beautiful-object-model http://this-plt-life.tumblr.com/post/41438931672/when-somebo...
- chrishenn 14y agoWhen I was learning more about this, I found this[1] article to be of great help. I think the key idea is that JS is a prototype-based OO model. It's easy to forget because there are so many abstractions[2] that act like a JS is a static class based OO language. [1] http://dmitrysoshnikov.com/ecmascript/chapter-7-1-oop-general-theory/ http://dmitrysoshnikov.com/ecmascript/chapter-7-1-oop-genera... [2] http://coffeescript.org/#classes http://coffeescript.org/#classes
- eaurouge 14y agoHis "behavior delegation" chain looks a lot like the method lookup chain [1] in Ruby, a pure object-oriented language. 1. http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html http://madebydna.com/all/code/2011/06/24/eigenclasses-demyst...
- mattdawson 14y agoThe same is true in Python - in single inheritance cases. (The rules for Python's method resolution order are more complex where multiple inheritance are involved[1].) 1. http://python-history.blogspot.com/2010/06/method-resolution-order.html http://python-history.blogspot.com/2010/06/method-resolution...
- dreamdu5t 14y agoJS is prototypical OO. There isn't supposed to be class inheritance. And no, Kyle Simpson is not a "legend." I've never even heard of him. Step outside your Twitter stream for a moment please.
- argonaut 14y agoDoes anyone know of a tutorial that breaks down (with code examples) all the different methods of JS inheritance and their disadvantages/advantages? I understand that Object.create is the now-recommended way to do things, but I still get confused because there are a bajillion ways of modeling inheritance in JS.
- tantalor 14y agoSome patterns off the top of my head, 1. Prototype 2. Delegate 3. Mixin 4. Module Understand how those patterns work and you should be able to understand how the libraries vary. Might also help: http://stackoverflow.com/questions/1645027/popular-javascript-inheritance-patterns http://stackoverflow.com/questions/1645027/popular-javascrip...
- wsc981 14y agoNice article. Never written much JavaScript myself, but as an Objective-C / iOS developer I understand the delegation part well, as it's an integral part of Apple's UIKit and AppKit API's. Though the concept was kind of alien to me before I started writing Objective-C code. A few years ago, when I started learning Objective-C I used a book written by Aaron Hillegass. I liked the way he explained delegation vs. subclassing: > Once upon a time (before Baywatch) there was a man with no name. Knight Industries decided that if this man were given guns and wheels and booster rockets, he would be the perfect crime-fighting tool. First they thought, "Let's subclass him and override everything we need to add the guns and wheels and booster rockets." The problem was to subclass Michael Knight, you would need to know an awful lot about his guts so that you could wire them to guns and booster rockets. So instead they created a helper object (delegate), the Knight Industries 2000 Super Car, or "Kitt." > Notice how this is different from the RoboCop approach. RoboCop was a man subclassed and extended. The whole RoboCop project involved dozens of surgeons to extend the man's brain into a fighting machine. This is the approach taken by many object-oriented frameworks. Source: Cocoa Programming for Mac OS X by Aaron Hillegass.
- ender7 14y ago"Inheritance" doesn't really exist in JS. We use that word because we don't have a better substitute, but what Javascript has is simply code sharing. You can share code between multiple objects. This is accomplished by using prototypes. An object has access to all the code defined on its prototype (and its prototype's prototype, and...). If two objects have the same prototype they will have access to the same methods. Now, unfortunately, the native Javascript way of saying "please set the prototype of this object to X" is not very intuitive. So again we reused an existing word -- "class" -- and defined it to be "a thing that creates an object and sets its prototype to be what I want". However, actually creating these class things is painful and verbose in vanilla Javascript, so everyone uses a library to do it for them. I use classdef [1] because I wrote it and it works just the way I want it to, but seriously there are a million options out there. Go find one and use it. [1] https://github.com/7sempra/classdef https://github.com/7sempra/classdef
- tantalor 14y agoI was taught that the practical purpose of inheritance is to share code. Nowadays we call that idea "DRY". Classical inheritance is a means to satisfy DRY. In JavaScript, the same concept exists, and it's sometimes called "prototypal inheritance" (since there are no classes). http://javascript.crockford.com/prototypal.html http://javascript.crockford.com/prototypal.html
- jefffoster 14y agoI've always thought inheritance is used to model is-a relationships. Sharing code may be a side effect, but it's certainly not the reason to use it. Using inheritance to share code is usually better achieved by factoring that code out to a separate object and having the objects in a inheritance relationship use it by composition.
- justincormack 14y agoHmm, interesting view. But why would you want to model is-a relationships? Other than to share code?
- estavaro 14y agoMy confession on the matter: Working with OO in JS made me a "cargo cultist." I wasn't entirely aware of how it worked, but just glad that it did for as long as I had used it. The last JS library I used was PrototypeJS which had some custom support for classes. I learned about non-OO JS code in the YUI framework. I didn't like what I saw as it precluded a lot of "private and hidden" code. I've deposited a lot of goodwill on the Dart language that compiles to JS. My reward is that Dart has library and class support that "just works! (TM)" Then again, I abhor the using of types that Dart allows as I think people waste a lot of time giving types to APIs and obscure the intention of the code, ultimately making the platform less popular.
- ahoge 14y ago>I think people waste a lot of time giving types to APIs and obscure the intention of the code What do you mean? Adding types to the surface area (arguments and return types) removes a lot of friction. I'm using jQuery for a couple of years. I still have to look at its docs almost every day I use it. Today, I had to check if the "selector" argument of "children()" is optional (spoiler: it is). Also, having the type annotations there makes the intention so much clearer. The name and the type of the argument is usually all you need to figure out what it does. I really like that about Dart.
- estavaro 14y agoThe problem is that it makes people more concerned about getting the types right than about giving people shortcuts. The API designers end up creating a multitude of APIs to deal with different type parameters and so on, to get their "generics" right and so on. It makes the APIs look like Java APIs more than they jQuery ones. Part of the problem is that the designers really want to get the types of classes and so on right on their parameters and return types. The types go beyond the primitives. I've been able to watch it unfold and it's rather painful. The result looks less like a scripting language API and more like a C# collection of libraries, for better or for worse.
- ahoge 14y ago
- 38leinad 14y agoI never find an answer to my most daunting question: how is the pattern for doing something like a super call in this prototypal model? bar.prototype.methodname? what if the method is only defined in the proto-prototype? I.e. Foo? Do I then have to explictly know this and write bar.prototype.prototype.methodname? I hope you know what I mean. This concept of super-calls does not transfer well to prototypal inheritance for me. Are there other patterns that should be used instead?
- TazeTSchnitzel 14y agoPrototypeClass.method.call(this)
- _getify 14y agoIn part 2, which should be published later today, I am going to address "polymorphism" directly, and the punchline is that I'm going to argue that JS doesn't have a good "OO" way of doing relative super calls, and thus you should try to avoid polymorphism. The workaround is indeed an implicit mixin, where you do "ParentConstructor.prototype.method.call(this)", but even though that "works", it's brittle to be hard-wiring your "inheritance" chain across all your polymorphic overridden methods.
- 38leinad 14y agothanks for the clarification. that helped a lot to get the understanding straight. always thought I am missing something fundamentally. Looking forward to the read. in the end i also think super-calls are not a very good concept as you normally don't know what the super calls are doing internally, but somehow it seems like the way to go as almost every mainstream language/framework is supporting/doing it... but i guess that's the general bitter taste i get from classical inheritance...
- pjmlp 14y agoThis problem is caused by developers only familiar with OO as it is presented by Object Pascal/C++/Java/C# and so on. There are however many other ways to do OO and JavaScript just happens to use another way. The language is not alone, Self, BETA, C@, Dylan, CLOS also have different ways from mainstream OO.
- davidwalshblog 14y agoPart 2 has been published: http://davidwalsh.name/javascript-objects-distractions http://davidwalsh.name/javascript-objects-distractions
- _getify 14y agoTo expound on the metaphor I put in this article about inheritance and my mother-in-law: > If you try to illustrate behavior delegation in terms of the "blueprint" metaphor, you quickly see how it totally breaks down. There's no way that my home, lacking a guest bedroom, could simply refer to another house, or to the original blueprints, to provide a bedroom for my mother-in-law when she comes to visit. OTOH, I can delegate my mother-in-law to go stay in a hotel room. Or, I can delegate my mother-in-law to stay on a neighbor's couch, but I can send along sheets and pillows for her to use. In either case, I'm not mutating my own home (inheritance) to handle her visit, I'm relying on someone else to handle it. But it's still my mother-in-law who I send elsewhere, and in fact, I can make sure she takes some "context" (aka, pillows) with her when she does. Again, metaphors are never perfect, but I just thought I'd complete the perspective to contrast inheritance vs. behavior delegation.