Tuesday, April 6th, 2010

Prototype 2.0 will not extend the DOM

<blockquote>

DOM extension is one of the biggest mistakes Prototype.js has ever done.

The above quote comes from the infamous Kangax (of Prototype Core).

He kindly goes into graphic detail on why it is heinous, and how Prototype 2.0 will not follow this mistake.

Although it seemed great, in practice it didn’t work because of:

  • Cross browser: host objects have no rules, IE DOM is a mess, etc
  • Change of collisions
  • Performance overhead

Extending DOM in controlled environment sure seems like a perfectly healthy thing to do. But even though the main problem is that with collisions, I would still advise to employ wrappers instead. It’s a safer way to move forward, and will save you from maintenance overhead in the future.

I look forward to seeing some examples of how usage of Prototype 2.0 would look. One of the things that I love about the Prototype library is the developer ergonomics. I personally much prefer element.foo() versus Lib.foo(element) even though they look similar. I look at a page of code and you see hundred of Lib.

Related Content:

Posted by Dion Almaer at 6:11 am
20 Comments

+++--
3.8 rating from 32 votes

20 Comments »

Comments feed TrackBack URI

Took them a few years to look around and reflect, better late then never I guess. Looking forward to Prototype 2, hopefully it’ll take care of all past design flaws.

Comment by Jadet — April 6, 2010

So when is Mootools gonna catch on?

Comment by RyanMorr — April 6, 2010

The DOM extension feel is one of the reasons I like Prototype more than jQuery. I hope Prototype 2.0 has some kind of uniqueness after this move. If it’s just jQuery by any other name, I’m not sure what the purpose is of having two libraries.

I look forward to seeing how it’s going to work in the future.

Comment by vvtim — April 6, 2010

Damn. I loved DOM extension. And it never caused me a problem. I guess I can just do my own DOM extensions when prototype 2.0 comes along

Comment by AngusC — April 6, 2010

@ryan – I can’t speak (with any certainly) on behalf of the MooTools crowd, but I’m pretty sure they see prototype extension as a design feature. I certainly wouldn’t want to use MooTools if they ‘catch on’…

Comment by sixtyseconds — April 6, 2010

@sixtyseconds – On the other hand I and perhaps others might want to use MooTools if they do ‘catch on’. Bottom line is, if I have to sacrifice a little syntactic sugar for a faster and more reliable framework, than I would do it. Wouldn’t you? Shouldn’t you?

Comment by RyanMorr — April 6, 2010

I personally much prefer element.foo() versus Lib.foo(element) even though they look similar.

The DOM extension feel is one of the reasons I like Prototype more than jQuery.

They don’t have to switch to Lib.foo(element). $ and $$ will probably return element wrappers instead of extended elements so that you can keep on using $(element).foo().

The difference is you’ll have to keep on using $(element) throughout the rest of your code since the actual element is never extended.

Comment by Jadet — April 6, 2010

1. To repeat the above question, what is Prototype.js’ selling point now? The iterators? The string functions? The classical OOP emulation? Those are all available on better (IMO) or at the very least better supported libraries.

2. Why not use sandboxed natives? I recall reading that MooTools was going in that direction.

Comment by SashaSklar — April 6, 2010

@jadet and others: working with elements won’t change much, since you still had to select them with $ or $$ before working with them. What goes away is the nice syntactic sugar around enumerables (objects and arrays) and String.

Comment by SashaSklar — April 6, 2010

@SashaSklar: Kangax only mentions wrappers for Element and Event, he doesn’t talk about adding sugar around Array or Object.

I hope Prototype takes care of that as well and moves towards getting rid of extending prototypes all together. Like the move to element wrappers that would make a lot of people happy for reasons Kangax can write up a whole new article. But it cramps Prototype’s style a bit, how much is all up to the implementation. Maybe something like P2() could go alongside the Scripty2 S2 namespace.

P2(fn).bind, P2([]).each, P2(.5).round(), P2(' ').strip().

Prototype Core can probably come up with better ideas.

Comment by Jadet — April 6, 2010

@Jadet:
IMHO, Prototype’s implementation of Enumerable and its way of mixing this into native objects is a great strength and a helpful feature. I don’t see how it causes any trouble, other than breaking enumeration via “for (var i in myArray) { … }”, which we shouldn’t be using anyway. I’ve also heard complaints about namespacing conflicts (like when attempting to use multiple libraries simultaneously) — two libraries attempting to write a method of the same name might cause issues.
.
To me, there isn’t any difference between extending Prototype’s objects and adding methods to native Ruby types, which is a convenient and helpful feature of Ruby IMHO.
.
What’s wrong with extending the object/array/string prototypes?

Comment by pianoroy — April 6, 2010

Before I got to know JQuery (at loong time ago), I used Prototype and quite loved it. But I noticed the performance issue with extending the DOM, so I made my own framework and got ride of $(‘myid’).getHeight() for Alias.Elm.getHeight(_(‘id’)).
While it is more complicated, you are so well impressed by the performances that you take the step easily. Nowadays I still use my framework, and I’m glad to see Prototype going the way.

Comment by Geompse — April 6, 2010

@pianoroy:
You already mention some of the problems yourself. Its best to avoid touching code you don’t have exclusive access to. Especially libraries should avoid exposing to global prototypes. Convenience is nice but it would be nicer if people could opt into that.

Comment by Jadet — April 6, 2010

I don’t use the framework at all, but speaking purely of preference, I like ExtJS’ implementation for elements. A simple wrapper class that holds a reference to the element gives you the el.getHeight() awesomeness without extending any native prototypes.

Not the fastest solution as you have to instantiate a new object for every element (they implement flyweights for handling large amounts of elements), but if used sparingly, I think its a decent alternative.

Just some food for thought.

Comment by RyanMorr — April 6, 2010

One idea would be for Prototype’s Element constructor to return an element within a wrapper class (as mentioned above), yet maintain the ability to call the wrapper’s methods as generic functions. That way instantiation isn’t required, it’s just available for those wanting the syntactic sugar.

Comment by mjuhl — April 6, 2010

…if I have to sacrifice a little syntactic sugar for a faster and more reliable framework…

Thing is, though, that choosing to not extend the DOM won’t speed up your framework — it’ll just bring everything into the same (slow) line. Your performance in browsers that do support this type of extension will suffer, as there’s a certain level of overhead associated with each call.

One of the commenters (Voloko) on the original article gives this example:
$(thing).mouseover(function(e) {
$(this).doSomething() // you end up creating a wrapper here for the same element over and over again.
}

Whilst it is possible to rewrite this so that you cache the wrapped “thing”, that is, in my opinion at least, unnecessarily complex and unintuitive.

For those interested, there’s a discussion in the MooTools mailing list available here. Interestingly, Fabio points out that the new Slick selector engine will have a public API for node selection sans extension, which will allow you to keep your performance high in IE.

Comment by barryvan — April 6, 2010

@barryvan It’s not that complex, really.

function ElementWrapper (element) {
...
}
function $ (thing) {
if (thing.constructor === ElementWrapper) {
return thing;
} else {
return new ElementWrapper(thing);
}
}

Comment by mjuhl — April 6, 2010

@barryvan: if the mouseover handler executes in the scope of the wrapped object, there’s no performance problem, it only needs to be created once.

Comment by Joeri — April 7, 2010

Prototype 2.0 ?

Humm, some change appear in prototype 1.7. array toJson has been removed, because arrays seem to already not extend the DOM.

http://groups.google.com/group/prototype-core/browse_thread/thread/13e48056f57f57d4

Comment by babooon — April 7, 2010

This is an interesting move for Prototype.

It always seemed to me like it was idealistic choice to go with Prototype. If you wanted to munge your global namespace a little and mess with DOM Nodes (to make the DOM work *theoretically* the same in all browsers), you used Prototype and triggered some hasOwnProperty() issues – but it was worth it.

Now that they are not changing the DOM to make things work the same way, I don’t know why someone would choose it over a library like jQuery that has more active development. I understand Kangax’s choice, but it’s almost like admitting their best feature was a flaw…

Comment by danbeam — April 7, 2010

Leave a comment

You must be logged in to post a comment.