MooTools: An Objective Look


D

David Mark

MooTools: An Objective Look

Seems this oddity is now creeping into public perception. So is it
any good at all?

As an aside, the "builder" is enhanced to the point of inaccessibility
and it is one of those pages that is falling off the edge of the left
side of the window (at least in FF3.) Not promising.

Excerpts:

- Some functionality inspired by [Prototype.js](http://
prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License]
(http://opensource.org/licenses/mit-license.php)
*/

There's a big red flag right off the bat.

var Hash = new Native({
name: 'Hash',

initialize: function(object){
if ($type(object) == 'hash') object = $unlink(object.getClean());
for (var key in object) this[key] = object[key];
return this;
}

});

They are aping the initial effort of a Javascript programmer who
obviously hadn't yet learned Javascript. Note the incessant use of
"$" as well as the "initialize" method.

And why isn't that for-in loop filtered? This is supposed to be a
drop-in solution, yet it is clearly vulnerable to the machinations of
other scripts.

function $arguments(i){
return function(){
return arguments;
};
};

Useless syntactic sugar (and for what?)

function $chk(obj){
return !!(obj || obj === 0);
};

Try to guess what that's for. Then wonder how it came to be called
"$chk".

function $defined(obj){
return (obj != undefined);
};

Hard to botch a one-line function such as this, but I spot no less
than four mistakes, including the aforementioned use of "$".

function $lambda(value){
return (typeof value == 'function') ? value : function(){
return value;
};
};

So why would you pass a function to this in the first place?

function $splat(obj){
var type = $type(obj);
return (type) ? ((type != 'array' && type != 'arguments') ? [obj] :
obj) : [];
};

Splat indeed.

function $try(){
for (var i = 0, l = arguments.length; i < l; i++){
try {
return arguments();
} catch(e){}
}
return null;
};

That lets out a lot of older browsers (syntax error) and it appears to
be part of the core.

function $type(obj){
if (obj == undefined) return false;
if (obj.$family) return (obj.$family.name == 'number' && !isFinite
(obj)) ? false : obj.$family.name;
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' :
'whitespace';
}
} else if (typeof obj.length == 'number'){
if (obj.callee) return 'arguments';
else if (obj.item) return 'collection';
}
return typeof obj;
};

I don't know what this is supposed to be, but I don't like it. And
something tells me the whole script hinges on it.

var Browser = $merge({

Engine: {name: 'unknown', version: 0},

Platform: {name: (window.orientation != undefined) ? 'ipod' :
(navigator.platform.match(/mac|win|linux/i) || ['other'])
[0].toLowerCase()},

Here we go.

Features: {xpath: !!(document.evaluate), air: !!(window.runtime),
query: !!(document.querySelector)},

This is stupid. Methods that rely on missing features should
themselves be missing from the API. No extraneous collection of flags
necessary.

Plugins: {},

Engines: {

Wonder how many the authors have heard of (and how many they know how
to detect?)

presto: function(){
return (!window.opera) ? false : ((arguments.callee.caller) ? 960 :
((document.getElementsByClassName) ? 950 : 925));

Jesus. The versions?!

},

There's none.

trident: function(){
return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ?
5 : 4);
},

And none.

webkit: function(){
return (navigator.taintEnabled) ? false :
((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) :
419);
},

Still none.

gecko: function(){
return (document.getBoxObjectFor == undefined) ? false :
((document.getElementsByClassName) ? 19 : 18);

The gBOF method is deprecated and will be removed in the next release
of FF. So this "detection" already has an expiration date.

}

And none. So, this was all a waste of time.

}

}, Browser || {});

Browser.Platform[Browser.Platform.name] = true;

For your sniffing convenience.

Browser.detect = function(){

for (var engine in this.Engines){
var version = this.Engines[engine]();
if (version){
this.Engine = {name: engine, version: version};
this.Engine[engine] = this.Engine[engine + version] = true;
break;
}
}

return {name: engine, version: version};

};

Browser.detect();

Well, at least they are honest about it. This doesn't even aspire to
be cross-browser (or maintainable.)

Browser.Features.xhr = !!(Browser.Request());

Another extraneous flag.

Browser.Plugins.Flash = (function(){
var version = ($try(function(){
return navigator.plugins['Shockwave Flash'].description;
}, function(){
return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable
('$version');
}) || '0 r0').match(/\d+/g);
return {version: parseInt(version[0] || 0 + '.' + version[1] || 0),
build: parseInt(version[2] || 0)};
})();

That dog don't hunt. The first "try" doesn't need try-catch and the
second is just wrong. Granted, Adobe's own examples are abominable,
but they at least attempt to address the myriad issues involved with
sniffing Flash.

function $exec(text){
if (!text) return text;
if (window.execScript){
window.execScript(text);
} else {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');

Why would anyone use setAttribute for this? Perhaps because dot
notation wouldn't work.

script[(Browser.Engine.webkit && Browser.Engine.version < 420) ?
'innerText' : 'text'] = text;

Now we see the incompetence inherent in the system. And how old is
this script? You can't buy that sort of ineptitude, so why not
download it for free?

document.head.appendChild(script);
document.head.removeChild(script);
}
return text;
};

var $uid = (Browser.Engine.trident) ? function(item){
return (item.uid || (item.uid = [Native.UID++]))[0];
} : function(item){
return item.uid || (item.uid = Native.UID++);
};

Similar nonsense.

var Window = new Native({

name: 'Window',

legacy: (Browser.Engine.trident) ? null: window.Window,

Isn't that something.

initialize: function(win){
$uid(win);
if (!win.Element){
win.Element = $empty;
if (Browser.Engine.webkit) win.document.createElement("iframe"); //
fixes safari 2

Oh I bet it does. And what of Safari 3? And WTF are they trying to
fix?

win.Element.prototype = (Browser.Engine.webkit) ? window
["[[DOMElement.prototype]]"] : {};

That does it.

}
win.document.window = win;

A document expando to boot. And that sure looks like a circular
reference to me.

return $extend(win, Window.Prototype);
},

I don't think it warrants any further study or consideration.
 
Ad

Advertisements

P

Peter Michaux

Hard to botch a one-line function such as this, but I spot no less
than four mistakes, including the aforementioned use of "$".

ECMAScript 3.1 spec removes the line about dollar sign is only for
machine generated code. The dollar sign will just be another
identifier character. I think this is a good change to the spec as
they should only state what is allowed and disallowed by a compliant
implementation.

Peter
 
D

dhtml

David said:
MooTools: An Objective Look

Seems this oddity is now creeping into public perception. So is it
any good at all?

* Modification of built-ins.
* Modification to host object (and assoc. prototype)
* Low level typechecking gone wrong ($type).
* Incorrect use of comparison operator everywhere (== where === is needed)

The name "MooTools" comes from "My OO Tools". It does not seem very OO.
The library creates a lot of low-level dependencies on built-ins and
host obj prototypes.

And why isn't that for-in loop filtered? This is supposed to be a
drop-in solution, yet it is clearly vulnerable to the machinations of
other scripts.


There are a lot of beginner mistakes like that:
* Something named 'Hash' should be checking own-properties only.
* The use of == where === should be used is
function $defined(obj){
return (obj != undefined);
};

Hard to botch a one-line function such as this, but I spot no less
than four mistakes, including the aforementioned use of "$".

1) the use of != where !== must be used
2) extra empty statement (the xtra ;).

The unneeded grouping is not a problem. I don't know if you're counting
that as a mistake.

function $try(){
for (var i = 0, l = arguments.length; i < l; i++){
try {
return arguments();
} catch(e){}
}
return null;
};


I understand that the mootools library uses tabs, but you could have
used a simple find-replace for the formatting.
That lets out a lot of older browsers (syntax error) and it appears to
be part of the core.

function $type(obj){
if (obj == undefined) return false;

boolean.
- If obj is null or undefined, false is returned.
if (obj.$family) return (obj.$family.name == 'number' && !isFinite
(obj)) ? false : obj.$family.name;

boolean || string.
- if obj has a $family property, if not finite, return false,
otherwise, return "number".
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' :
'whitespace';
}
} else if (typeof obj.length == 'number'){
if (obj.callee) return 'arguments';
else if (obj.item) return 'collection';
}
return typeof obj;
string.

};

I don't know what this is supposed to be, but I don't like it.

Function $type is a low-level utility used for typechecking. The
function returns either a string or a boolean (I find this to be ironic).

There is a bug in the clause:-
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ?
'textnode' : 'whitespace';

.. Because obj.nodeType is 3, it will return either 'textnode' or
'whitespace'. They are consider '\u00a0', '\n', and other things to be
'textnode' not 'whitespace'. This is tricky, because it is unclear who
would be interested in '\n', and who would not want to care about that.
It places concern about what the callee might be doing with this value.
It is very non-OO.

The built-ins' prototypes, such as Array.prototype, are modified with a
$family property so that when $type is called, it can access that
property off the prototype chain of the object.

Being such a core part of a library named "My OO Tools", it indicates a
strong contradiction to the library's name.
Now we see the incompetence inherent in the system. And how old is
this script? You can't buy that sort of ineptitude, so why not
download it for free?

document.head.appendChild(script);
document.head.removeChild(script);
}
return text;
};

The head property was added to the document by this script. That side
effect isn't justified by the benefit obtained (less typing).

Similar nonsense.

var Window = new Native({

name: 'Window',

legacy: (Browser.Engine.trident) ? null: window.Window,

Isn't that something.

initialize: function(win){
$uid(win);
if (!win.Element){
win.Element = $empty;
if (Browser.Engine.webkit) win.document.createElement("iframe"); //
fixes safari 2

Oh I bet it does. And what of Safari 3? And WTF are they trying to
fix?

win.Element.prototype = (Browser.Engine.webkit) ? window
["[[DOMElement.prototype]]"] : {};

That does it.

Modifying Host objects' prototype, and expecting the result to be that
the element will have, in the prototype chain, the property, but only
after browser sniffing. A lot of risky inferences. This approach is
totally unnecessary.

}
win.document.window = win;

A document expando to boot. And that sure looks like a circular
reference to me.

return $extend(win, Window.Prototype);
},

I don't think it warrants any further study or consideration.

It is taken seriously. It was discussed at a recent 'JS Meetup' here in
SF, as is the cappucino framework, and its authors who frequently
present there (we can discuss this one next week).

It is somewhat useful to study this library because it is taken
seriously. If you reply to a job inquiry, and you get asked a silly
question like 'how is your mootools on a 1 to 10', you are ready with a
relaxed, objective, well-informed response (try not to laugh too much).

Garrett
 
D

David Mark

* Modification of built-ins.
* Modification to host object (and assoc. prototype)
* Low level typechecking gone wrong ($type).
* Incorrect use of comparison operator everywhere (== where ===is needed)

The name "MooTools" comes from "My OO Tools". It does not seem very OO.
The library creates a lot of low-level dependencies on built-ins and
host obj prototypes.

Yes. Looked pretty inefficient and inflexible to me for this reason.
And of course, the host object prototype stuff is madness.
There are a lot of beginner mistakes like that:
  * Something named 'Hash' should be checking own-properties only.
  * The use of == where === should be used is





1) the use of != where !== must be used
2) extra empty statement (the xtra ;).

LOL. Thanks. Five mistakes (how did I miss that one!) Those two,
plus:

3. The "$"
4. The unneeded parentheses
5. Use of undefined identifier will break some older agents (typeof
should be used in such low-level code)
The unneeded grouping is not a problem. I don't know if you're counting
that as a mistake.

Yes. I was being picky on some of those.
function $try(){
   for (var i = 0, l = arguments.length; i < l; i++){
           try {
                   return arguments();
           } catch(e){}
   }
   return null;
};


I understand that the mootools library uses tabs, but you could have
used a simple find-replace for the formatting.


Sorry about that.
boolean.
  - If obj is null or undefined, false is returned.


boolean || string.
  - if obj has a $family property, if not finite, return false,
otherwise, return "number".


Function $type is a low-level utility used for typechecking. The
function returns either a string or a boolean (I find this to be ironic).

Yes. Do you then call $type again to check the type of result?!
There is a bug in the clause:-
   switch (obj.nodeType){
     case 1: return 'element';
     case 3: return (/\S/).test(obj.nodeValue) ?
     'textnode' :  'whitespace';

. Because obj.nodeType is 3, it will return either 'textnode' or
'whitespace'. They are consider '\u00a0', '\n', and other things to be
'textnode' not 'whitespace'. This is tricky, because it is unclear who
would be interested in '\n', and who would not want to care about that.
It places concern about what the callee might be doing with this value.
It is very non-OO.

I may not know OO, but I know what I like (and this ain't it.)
The built-ins' prototypes, such as Array.prototype, are modified with a
$family property so that when $type is called, it can access that
property off the prototype chain of the object.

Being such a core part of a library named "My OO Tools", it indicates a
strong contradiction to the library's name.



The head property was added to the document by this script. That side

Unbelievable. I missed that one as I was focused on the browser
sniffing that preceded it.
effect isn't justified by the benefit obtained (less typing).

And of course, if document.expando is false in IE...
Similar nonsense.
var Window = new Native({
   name: 'Window',
   legacy: (Browser.Engine.trident) ? null: window.Window,
Isn't that something.
   initialize: function(win){
           $uid(win);
           if (!win.Element){
                   win.Element = $empty;
                   if (Browser.Engine.webkit) win.document.createElement("iframe"); //
fixes safari 2
Oh I bet it does.  And what of Safari 3?  And WTF are they trying to
fix?
                   win.Element.prototype = (Browser.Engine.webkit) ? window
["[[DOMElement.prototype]]"] : {};
That does it.

Modifying Host objects' prototype, and expecting the result to be that
the element will have, in the prototype chain, the property, but only
after browser sniffing. A lot of risky inferences. This approach is
totally unnecessary.

I think you are being too kind.
It is taken seriously. It was discussed at a recent 'JS Meetup' here in

I know. The old "Prototype vs. jQuery" shriek-fest seems to have
"evolved" to include this thing. It seems the worse the script, the
more people blindly swear by it.
SF, as is the cappucino framework, and its authors who frequently
present there (we can discuss this one next week).

Never looked at that one.
It is somewhat useful to study this library because it is taken
seriously. If you reply to a job inquiry, and you get asked a silly
question like 'how is your mootools on a 1 to 10', you are ready with a
relaxed, objective, well-informed response (try not to laugh too much).

I agree in part, but seriously think that most HR types (or even IT
managers) would smile and award the applicant a 0 for that "skill."
 
G

Gregor Kofler

dhtml meinte:
It is somewhat useful to study this library because it is taken
seriously. If you reply to a job inquiry, and you get asked a silly
question like 'how is your mootools on a 1 to 10', you are ready with a
relaxed, objective, well-informed response (try not to laugh too much).

Ah, I'm sure they'd like to hear you stating you were a MooTools
aficionado from version 0.0.1 on. But then: You probably don't want to
have that very job. (After getting close to a job of fixing IE memory
leaks in a Spry-prototype/scriptaculous-jQuery application, I definitely
know what to despise.)

Gregor
 
M

Matt Kruse

ECMAScript 3.1 spec removes the line about dollar sign is only for
machine generated code.

This is good news! One less thing to nit-pick and argue about here ;)

Matt Kruse
 
Ad

Advertisements

D

David Mark

dhtml meinte:


Ah, I'm sure they'd like to hear you stating you were a MooTools
aficionado from version 0.0.1 on. But then: You probably don't want to
have that very job. (After getting close to a job of fixing IE memory
leaks in a Spry-prototype/scriptaculous-jQuery application, I definitely
know what to despise.)

I bet that was something. Of course, it won't be something for very
long.

Maybe this would be a good visual aid for an interview:

http://farm4.static.flickr.com/3211/2347642183_91247aa0c8_o.jpg
 
D

David Mark

[snip]
It is taken seriously. It was discussed at a recent 'JS Meetup' here in
SF, as is the cappucino framework, and its authors who frequently
present there (we can discuss this one next week).

No time like the present. As for the download page, these framework
authors don't believe in left margins do they?

An excerpt from their flagship demo:

<script type="text/javascript" charset="utf-8">
//create a new timestamp to monitor launch time
_LAUNCH_TIME = new Date();

var path = document.location.href;

Not a good start. Using document.location (as opposed to
window.location) is the mark of a know-nothing.

path = path.substr(0, path.lastIndexOf('/') + 1);

document.write( said:
<"+"/base><![endif]-->");

As is unnecessary concatenation.

</script>

<script src = "Frameworks/Objective-J/Objective-J.js" type = "text/
javascript"></script>

Nice markup.

Excerpt from "Objective J":

var NO = false,
YES = true,
nil = null,
Nil = null,
NULL = null,
ABS = Math.abs,
ASIN = Math.asin,
ACOS = Math.acos,
ATAN = Math.atan,
ATAN2 = Math.atan2,
SIN = Math.sin,
COS = Math.cos,
TAN = Math.tan,
EXP = Math.exp,
POW = Math.pow,
CEIL = Math.ceil,
FLOOR = Math.floor,
ROUND = Math.round,
MIN = Math.min,
MAX = Math.max,
RAND = Math.random,
SQRT = Math.sqrt,
E = Math.E,
LN2 = Math.LN2,
LN10 = Math.LN10,
LOG2E = Math.LOG2E,
LOG10E = Math.LOG10E,
PI = Math.PI,
PI2 = Math.PI * 2.0,
PI_2 = Math.PI / 2.0,
SQRT1_2 = Math.SQRT1_2,
SQRT2 = Math.SQRT2;

WTF?

var objj_continue_alerting = NO;

Yeah, I guess "false" is harder on the fingers.

with (new prototype_bug())
member = true;

Ugh.

if (window.ActiveXObject) {

Ineffectual feature detection.

if (window.XMLHttpRequest) {

Again.

objj_request_xmlhttp = function()
{
return new XMLHttpRequest();
}
} else if (window.ActiveXObject) {
var MSXML_XMLHTTP_OBJECTS = [ "Microsoft.XMLHTTP", "Msxml2.XMLHTTP",
"Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP.6.0" ],

Second one isn't needed.

index = MSXML_XMLHTTP_OBJECTS.length;
while (index--)
{
try
{
new ActiveXObject(MSXML_XMLHTTP_OBJECTS[index]);
break;
}
catch (anException)
{
}
}
var MSXML_XMLHTTP = MSXML_XMLHTTP_OBJECTS[index];
delete index;
delete MSXML_XMLHTTP_OBJECTS;

I've seen enough.

[snip]
 
M

Matt Kruse

MooTools: An Objective Look

I would be interested to see you look at jQuery again after the next
1.3 release (as will I, but I haven't done so yet). They are cleaning
out all browser sniffing, from what I can tell, and making an effort
to use better coding practices.

Of course, some of the design decisions will still be disagreed with
(overloading functions, use of $, supporting only a subset of known
browsers, etc). But is seems like they are trying to address some of
the coding concerns expressed here and by others.

The nice thing about a public library with a community and a group of
developers is that it can grow and improve and become more robust over
time. Hopefully.

Matt Kruse
 
D

David Mark

I would be interested to see you look at jQuery again after the next
1.3 release (as will I, but I haven't done so yet). They are cleaning

Let me know when it is released and I will.
out all browser sniffing, from what I can tell, and making an effort

If they swap UA-parsing for poor object inferences like MooTools, it
won't really represent progress (okay, maybe a tiny bit.)
to use better coding practices.

That would be nice, but you have to feel for the site and widget
authors who will have to re-test everything.
Of course, some of the design decisions will still be disagreed with
(overloading functions, use of $, supporting only a subset of known

I really couldn't care less about "$". That's just a symbol of
incompetence. It's the real problems that bother me.
browsers, etc). But is seems like they are trying to address some of
the coding concerns expressed here and by others.

I've heard that before. We'll see.
The nice thing about a public library with a community and a group of
developers is that it can grow and improve and become more robust over
time. Hopefully.

Depends on the developers.
 
D

David Mark

I would be interested to see you look at jQuery again after the next
1.3 release (as will I, but I haven't done so yet). They are cleaning
out all browser sniffing, from what I can tell, and making an effort
to use better coding practices.

[snip]

I see the discussions. The sniffing is officially deprecated (along
with the box model detection which I pointed out as ludicrous a full
year ago), though still available for abuse (and the box model stuff
affects some of the core features.) I see a lot of clueless people
arguing for sniffing because of quirks they can't detect with feature
testing. The answer to that is obvious (don't encapsulate such things
in a browser scripting library.)

It is ironic that John Resig is finally trying to follow the road map
laid out a year back, which he dismissed as minor quibbling at the
time.

I was told of a similar effort by the Prototype crowd a few weeks
ago. As it turned out, something called "Kangax" had appropriated a
bit of my code and then veered off into pure fantasy. So the fact
that some of the jQuery developers have had a similar epiphany doesn't
mean much until they follow through with competently written feature
testing code.

Perhaps I will change the licensing requirements for My Library (and
finish the documentation of course.) It seems silly for most of the
world to hold their breath for a competent version of a script that
could have eliminated browser sniffing years ago. And, as mentioned,
there are lots of other problems with the jQuery design that can't be
addressed by patching.

And I still think that learning browser scripting is preferable to
using any prefab library or framework.
 
Ad

Advertisements

D

David Mark

David Mark wrote:

[snip]
I was told of a similar effort by the Prototype crowd a few weeks
ago.  As it turned out, something called "Kangax" had appropriated a
bit of my code and then veered off into pure fantasy.  So the fact

I don't recall Micheaux' article (which `isHostMethod` was taken from
and which I linked to from the blog post) mentioning any specific
license or copyright. Granted, he does talk about you participating in
feature detection-related dicsussions, but there's no mention of any

I'm pretty sure he mentions that isHostMethod is mine. And if you
trace the lineage, it is based on a method recommended by Thomas that
first appeared here several years ago.
kind of authorship that `isHostMethod` (and others) must retain. So what
exactly are you talking about?

I didn't imply an legal liability for using it. After all, it was
first published to this newsgroup. Ironically, your feature testing
code doesn't call it at all. Is it meant to be window dressing?

It is also ironic to see the product of discussions in this group
appearing in these library efforts. When exactly did the "real world"
change its collective tune? I see that the Dojo developers still live
in Fantasyland though (they reportedly laughed at Resig's "revelation"
about browser sniffing at a recent conference.)
Having said that, I do realize that my code must be full of stupid
mistakes, and would gladly listen to what you find delusional in my
"pure fantasy".

Search the archive. I commented on it after it was mentioned as a
sign that Prototype was attempting to move away from browser
sniffing. And if you are going to use one of my methods, why not just
use my library? What possible use is there in propping up a falling
star like Prototype?

[snip]
 
D

David Mark

David said:
David Mark wrote:
[snip]
I was told of a similar effort by the Prototype crowd a few weeks
ago.  As it turned out, something called "Kangax" had appropriated a
bit of my code and then veered off into pure fantasy.  So the fact
I don't recall Micheaux' article (which `isHostMethod` was taken from
and which I linked to from the blog post) mentioning any specific
license or copyright. Granted, he does talk about you participating in
feature detection-related dicsussions, but there's no mention of any
I'm pretty sure he mentions that isHostMethod is mine.  And if you
trace the lineage, it is based on a method recommended by Thomas that
first appeared here several years ago.

Yes, I've read through the archives after you brought this up the first
time. Perhaps I should have paid more attention to script's origins and
put a note in the source, but since I wasn't even using it (as you
obviously noticed) it didn't seem so important.

No. I don't care if you put a note in there or not. I was simply
noting that you included one of my library's methods and then failed
to call it at all.
It was meant to replace plain boolean type conversion. While known to be

Yes, I know (I wrote it.)
error-prone in certain cases, boolean type conversion seems more than
enough in such limited set of tests. Are there any known environments
where, say, `document.createElement` needs to be tested with `typeof`?

Wouldn't matter if there weren't. But if you read about the origins
of this technique, you will find lots of cases where boolean type
conversion of host methods blows up (all are found in IE.)
Yes, I was at that conference. I remember all four speakers (of
different libraries) talking about cases where browser sniffing can not
be avoided.

And all can be considered ignorant for attempting to encapsulate such
cases in browser scripting libraries (assuming the cases really aren't
reconcilable with feature testing.) What I want to know is why anyone
would listen to them at this point (let alone pay money for the
privilege.) Seems more like a freak show than a conference.
Ok. I'll read through it.

Post questions if you have any. And good luck convincing the
Prototype authors to give up their addiction to browser sniffing.
sniffing.  And if you are going to use one of my methods, why not just
use my library?  What possible use is there in propping up a falling

I am using Garrett's APE [1] in some of the projects. I find it a great

I have to figure that is a much more solid choice than Prototripe. I
have no experience with his library, but I doubt it contains the sorts
of blunders found in the "big four."
base to build upon (although I told him about clients in which it fails
- e.g. older Safari due to lack of `hasOwnProperty`). I need to find
some time to read through your library.


I don't have executive decisions rights in Prototype.js development. Its
core understands some of the major flaws in library design (such as host
objects extension, sniffing and unnecessary low-level abstractions). It

Then why does it still use sniffing and unnecessary low-level
abstractions? It seems like *you* understand a bit about these
things, but the "core" is still focused on tired arguments against
feature testing.
would be much easier for us to make something decent out of it if not
for the the burden of backwards compatibility. Lack of time is another

I don't know what that means in relation to Prototype. It only claims
to support a few of the latest browsers and uses sniffing to create
the illusion that it does. There is nowhere to go but up from there.
Even John Resig seems to grasp that at this point.
show-stopper. Nevertheless, I think it's moving in the right direction.

Wherever it is going, it is doing so at a snail's pace. Same for
jQuery, but at least they are trying to turn in the right direction.

[snip]
 
K

Kenny

Matt said:
I would be interested to see you look at jQuery again after the next
1.3 release (as will I, but I haven't done so yet). They are cleaning
out all browser sniffing, from what I can tell, and making an effort
to use better coding practices.

Of course, some of the design decisions will still be disagreed with
(overloading functions, use of $, supporting only a subset of known
browsers, etc). But is seems like they are trying to address some of
the coding concerns expressed here and by others.

The naysayers would naysay that anyone who made the mistake of
browser-sniffing in the first place is by definition subhuman so the
entire framework must be dumped in the garbage. But what do we do when
Subhuman admits he should not be doing browser sniffing and tries to
cure? Are they still subhuman?

I am just happy I have an application to work on so I do not have to
worry about the answer.
The nice thing about a public library with a community and a group of
developers is that it can grow and improve and become more robust over
time. Hopefully.

Word. But (a quibble) there is not so much hope as there is a need to
(a) look at the core to see if it is salvageable and then (b) look at
the project to see if it is active. If all looks good, no hope is
needed: just add one's shoulder to the wheel. OK, I was not quibbling: I
hated YUI when I looked inside, which confirmed my experience from the
outside and the stream of tortured emails on the support list: YUI is a
library only its author can love and only because they wrote it.

kt
 
D

David Mark

The naysayers would naysay that anyone who made the mistake of
browser-sniffing in the first place is by definition subhuman so the

That is preposterous. Other than you now, who ever said such a
thing? However, it seems quite late in the game for the Web to
littered with scripts that stoop to such levels.
entire framework must be dumped in the garbage. But what do we do when

The jQuery "framework" is just a bad script. And yes it should be
thrown out, regardless of whether it finally jettisons the sniffing
nonsense.
Subhuman admits he should not be doing browser sniffing and tries to
cure? Are they still subhuman?

If you are referring to Resig. I don't think history will be kind as
he fought the idea for over a year and then announced *his* revelation
about feature testing. The tagline I saw was "They said it couldn't
be done." Who is "they?" Among others, I told him it could and
should be done and he responded that such ideas had no place in his
framework for the "real world." He's clearly a bit dim and
disingenuous, but more or less human.
I am just happy I have an application to work on so I do not have to
worry about the answer.

You could have just skipped the question.
Word. But (a quibble) there is not so much hope as there is a need to
(a) look at the core to see if it is salvageable and then (b) look at

In the case of jQuery, it is not salvageable.
the project to see if it is active. If all looks good, no hope is

Activity doesn't indicate much. How many widgets have been written
for the old jQuery version(s) in the last year? AIUI, many of them
use the browser flags exposed by jQuery. As the authors are now faced
with "deprecated" browser sniffing support, they are looking at
rewrites they are most likely incapable of doing (as evidenced by the
vocal resistance to this move.) And what about all of the Websites
that use these things? If they upgrade jQuery, will it break the
dependent widgets? Will newer versions of the widgets work with the
old jQuery? Is the average Web developer even conscious of these
issues?

What was the benefit of using jQuery again? To paraphrase one of the
Ajaxian editors in an article that dismissed any and all suggestions
of better frameworks: "these things have widgets." In other words,
that ship has sailed (never mind that it is sinking.)
needed: just add one's shoulder to the wheel. OK, I was not quibbling: I
hated YUI when I looked inside, which confirmed my experience from the

That is typical of your inability to judge code quality. I certainly
wouldn't recommend YUI (not even to Yahoo!), but it is definitely
better than that monstrosity you advocate.
outside and the stream of tortured emails on the support list: YUI is a

Tortured emails don't indicate much either. There will always be
people who are incapable of understanding, don't read the manual, etc.
library only its author can love and only because they wrote it.

Now there's a glimmer of insight. It's faint, but it's there.
 
T

Thomas 'PointedEars' Lahn

I don't know which built-ins you are referring to exactly here, but I don't
think there is anything *inherently* wrong with that. For a prominent
example, if Math.max() was detected not to support more than two arguments
in an implementation, and an application needed to determine the maximum out
of three or more values, I think it would be acceptable, if not prudent, to
try overwriting the built-in Math.max() with a method that is capable of
handling that (preferably storing the reference in another property, and
even reusing them in the replacement).
Yes. Looked pretty inefficient and inflexible to me for this reason.
And of course, the host object prototype stuff is madness.

I don't think there is anything *inherently* wrong with using the prototype
object of host objects when it is provided either; after all, we have to
assume that modification of existing features or augmentation with new
features is the reason why it was made publicly available by the vendor in
the first place, and the augmentation of prototype objects can be much more
efficient than using a wrapper object that provides the new feature.

The problem (or as you put it, the madness) begins when one assumes that
because a prototype object is provided by one DOM API (e.g., the Gecko DOM)
it must also be provided by another, and if not already there to try making
it so. Because the former would be object inference, and the latter would
be host object augmentation; as discussed already, both must be considered
error-prone.


PointedEars
 
Ad

Advertisements

T

Thomas 'PointedEars' Lahn

Peter said:
ECMAScript 3.1 spec removes the line about dollar sign is only for
machine generated code. The dollar sign will just be another
identifier character. I think this is a good change to the spec as
they should only state what is allowed and disallowed by a compliant
implementation.

I think that is a shortsighted argumentation out of lack of sufficient
experience on your part. Technical specifications before have often, if not
always, stated not only what was allowed for achieving conformance and what
wasn't, but also have made recommendations as to what to consider
appropriate according to its author(s), and to what extent. See also
RFC2119 -- "Key words for use in RFCs to Indicate Requirement Levels"[1].

As for the `$', while the recommendation to use it only as prefix in
machine-generated code may be debatable, it stands to reason that given the
number of different libraries around that use the standalone `$' as an
identifier already, it would be unwise to follow that practice in new
(library) code that is supposed to be compatible. And, in fact, it could be
argued that using the `$' in new identifiers might lead to confusion when
reading and using such library code.

As for ECMAScript Edition 3.1 (and 4), it remains to be seen when it will be
finished, and when first implemented in a production environment. Insofar
your argument is not much more than of an academic nature at this point, and
you would be well-advised, if not required by the current prose of its text,
to refer to this Edition, like other Working Drafts out there, only as work
in progress, and therefore subject to change and being declared obsolete at
any time. "ECMA-262 Editions 3.1 and 4 are the next-generation versions of
ECMAScript *being developed* currently by the ECMA TC39 committee."[1]


PointedEars
___________
[1] <http://rfc-editor.org/rfc/rfc2119.txt>
[2] <http://www.ecmascript.org/docs.php>
 
D

dhtml

Thomas said:
I don't know which built-ins you are referring to exactly here,

Please see the Mootools documentation or source code.

Some of the modifications make sense, like adding the array-extras, if
they don't exist.

Other modifications don't really seem useful and might even conflict
with new releases of the language (Function.prototype.bind, for example).
I don't think there is anything *inherently* wrong with using the prototype
object of host objects when it is provided either; after all, we have to
assume that modification of existing features or augmentation with new
features is the reason why it was made publicly available by the vendor in

We don't have to assume anything.

It seems more likely (to me) that Mozilla exposed the XPConnect wrapped
prototypes so that developers could write quick patches.
the first place, and the augmentation of prototype objects can be much more
efficient than using a wrapper object that provides the new feature.

Example:

Element.prototype.customMeth = function(){ }

Do not do this. Augmenting host objects is error-prone. (you've said so
yourself, below).

It is less clear which methods are native and which are user add-ons. It
has the effect of creating a big ball of mud.

A decorator or a static method is much clearer. That way those
methods/constructors can be imported on the page they are used.

You have provided no evidence that modifying a host object prototype
would be more efficient than creating a static method and passing an
element to that method. I'm inclined to think that the lookup of that
method would be less efficient, as the method property name would have
to be found on the prototype chain of the object (if it is not shadowed).
The problem (or as you put it, the madness) begins when one assumes that
because a prototype object is provided by one DOM API (e.g., the Gecko DOM)
it must also be provided by another, and if not already there to try making
it so. Because the former would be object inference, and the latter would
be host object augmentation; as discussed already, both must be considered
error-prone.

Yes, modifying host objects' prototypes is error-prone.
 
T

Thomas 'PointedEars' Lahn

dhtml said:
Please see the Mootools documentation or source code.

Maybe later.
Some of the modifications make sense, like adding the array-extras, if

they don't exist.

Other modifications don't really seem useful and might even conflict
with new releases of the language (Function.prototype.bind, for
example).

I was not arguing about the (doubtful) code quality of MooTools here but
about the -- I think -- inappropriate *general* criticism of some of the
design patterns it employs.
We don't have to assume anything.

That is also correct, but you miss the point.
It seems more likely (to me) that Mozilla exposed the XPConnect
wrapped
prototypes so that developers could write quick patches.

Now that does not make sense to me at all. Patches to the C++ or Java
source code of Mozilla can be easily written without the Gecko DOM
exposing host object's prototypes through ECMAScript binding. Are you
sure you know what you are talking about?
Example:

Element.prototype.customMeth = function(){ }

Do not do this.

Name a really good reason why not.
Augmenting host objects is error-prone. (you've said so yourself,
below).

That is NOT augmenting a host object.
It is less clear which methods are native and which are user add-ons.

Really? I think the enumerable ones are user-defined and vice-versa
(CMIIW, I can't test right now).
has the effect of creating a big ball of mud.

That is not an argument.
A decorator or a static method is much clearer.

Maybe so, but it is also more expensive in memory.
That way those
methods/constructors can be imported on the page they are used.

With augmenting a host object's prototype, a property/feature becomes
available for all corresponding elements in a *document* without costly
iteration. I see no good reason why not to make use of such a useful DOM
feature if it is available. (In fact, I think it has the capacity to
become a DOM standard.)
You have provided no evidence that modifying a host object prototype
would be more efficient than creating a static method and passing an
element to that method.

An element object reference, and the greater efficiency in this case
would seem to be self-evident.
I'm inclined to think that the lookup of that
method would be less efficient, as the method property name would have

to be found on the prototype chain of the object (if it is not
shadowed).

As always, the bargain is runtime efficiency vs. memory efficiency.
Yes, modifying host objects' prototypes is error-prone.

No, it isn't. Prototype objects are native objects.


PointedEars
 
Ad

Advertisements

D

dhtml

Thomas said:
I was not arguing about the (doubtful) code quality of MooTools here but
about the -- I think -- inappropriate *general* criticism of some of the
design patterns it employs.

What design patterns in Mootools were criticized?
Now that does not make sense to me at all. Patches to the C++ or Java
source code of Mozilla can be easily written without the Gecko DOM
exposing host object's prototypes through ECMAScript binding. Are you
sure you know what you are talking about?

Take the pageX/Y properties. Problems in Firefox were that it did not
include scroll. An experimental monkey patch:-

MouseEvent.prototype.__defineGetter__('pageX', function() {
return this.clientX + window.pageXOffset;
});
MouseEvent.prototype.__defineGetter__('pageY', function() {
return this.clientY + window.pageYOffset;
});

If the monkey patch worked, it could be later incorporated into a real
patch.

I would not want to rely on this for a real webapp, though. It would
require a lot of feature testing and would probably be easier to design
around the problem.
Really? I think the enumerable ones are user-defined and vice-versa
(CMIIW, I can't test right now).

Many DOM properties have a |readonly| flag. This flag can map to
ECMAScript {ReadOnly} attribute. However, there is nothing that maps to
ECMAScript {DontEnum} attribute. This is not defined for any dom
objects, and so it is entirely dependent on the implementation.

The Host object might have a property with the same name hidden away
somewhere else on the object or its prototype chain. It might have a
getter defined on that object itself.

If('
has the effect of creating a big ball of mud.

That is not an argument.

The design issue...

I don't have costly iteration in my scripts and I never augment
Element.prototype. It is a solution to a problem that does not exist.

"Big ball of mud" is packaging of everything together.

Changes to part of a package affect the entire "package" (I'm using the
term "package" to describe software that is released as a unit).

Packages should be grouped according to usage patterns are smaller and
more clearly defined in terms of scope. This offers a few benefits:-

1) Unit testing small, narrowly defined portions of code is easier.
2) Packages grouped according to usage patterns are smaller. They
download faster and take up less space in the cache.

The package can be released as a set of functions in a file, or a set of
files that are intended to be used together.

Closures lend themselves nicely to packaging. Things that do not need to
be shared can be kept private to the scope.

A dependency on a package is a dependency on everything in that package.
The biggest issues I have with most library code I see (even in my own)
is that the packages are too generalized. There is generally too much
generality.

Recent uses use of dojo, jQuery and Mootools that I have looked at used
only a small portion of the library. Of that small portion, only part of
the code paths were executed. What the author was trying to accomplish
could have been achieved with much less code than those functions that
the library used and far less code than the entire library. The library
itself was not needed and that even as used for the purpose the author
used it for. It was not pulling its weight and was an inefficient
solution to the problem.

If the author had pared down the library (by snipping unused functions),
the library code would still be more than what was needed. A author who
is going to take to pains paring down one of these libraries to only the
functions he needs is probably skilled enough to be able to write his
own solution.

I see no good reason why not to make use of such a useful DOM
feature if it is available. (In fact, I think it has the capacity to
become a DOM standard.)

It is becoming a DOM standard (WEB IDL). They will have a lot of work in
for themselves if they plan on defining the prototype chain for objects,
and which attributes will be present {ReadOnly, DontDelete, DontEnum}.

I wonder how they will map a DOM readonly property. Is that supposed to
be {ReadOnly}? Many of these dom readonly properties are implemented as
getters. For example, ElementCSSInlineStyle is a getter. A getter
behaves differently than a ES {ReadOnly} property. Assigning to a ES
{ReadOnly} property fails silently Assignment to a property that has a
getter but no setter results in TypeError in Mozilla JavaScript. Example:-

document.body.style=1
An element object reference, and the greater efficiency in this case
would seem to be self-evident.


As always, the bargain is runtime efficiency vs. memory efficiency.

Comparing:-

// 1.
Element.prototype.getX = function() { };
// 2.
function getX(el) { }

Where is the memory efficiency in #1?

Function getX (2) would not have to be resolved off the host object's
prototype chain. Element.prototype.getX would have to be resolved up the
prototype chain.
No, it isn't. Prototype objects are native objects.

Given a host object Element, Element.prototype does not have to be a
native object. This next example creates a user-defined function X,
creates a new Image() (a host object), and assigns that new Image to
X.prototype. Constructing a new X will result in a [[Prototype]]
property - X.prototype - on the new object:-

function X() {}
X.prototype = new Image;
"x" in new X;

The example shows that a prototype object of a native ES object may be a
Host object. A prototype of a Host object could also be a Host object,
though it could also be null, undefined, Object.prototype...

Running the example, the |in| expression -- "x" in new X -- may or may
not be true, depending on implementation. The |x| property might be
implemented as a setter or it might be implemented as a property
somewhere. There is no standard for that and implementations vary. That
would be up to the implementation.

Consider a case of a hypothetical user-defined property |x| on
Element.prototype, Element.prototype.x. When resolving an identifier |x|
on an img object, img.x, the |x| property would be not be resolved on
Element.prototype. Instead, it would more likely be found in
HTMLImageElement.prototype, or on the object itself. The |x| property
might be implemented as a getter or it might be implemented as a property.

Node
|
Element {x:Function(user-def} EventTarget
| |
HTMLElement {style::ElementCSSInlineStyle}
|
HTMLImageElement { getter x::uint }
|
img

If HTMLImageElement has an |x| property, then Element.prototype.x would
be resolved to the |x| property on HTMLImageElement, not to the one you
added.

There is not any |x| property defined by current w3c HTML dom
specifications for HTMLImageElement. Implementations cannot be expected
to define no extra properties. In fact, they do often do define other
properties. Nor can they be expected to not shadow properties, nor can
they be expected to define the properties as readonly, dontdelete. I
think it would be a bad idea to assume that implementations always map
DOM readonly to ES {ReadOnly) (and not implement that property as a
getter).

A method that accepts an element should be able to safely access the
element's properties withouth resolving user-defined property on a Host
object's prototype.

Garrett
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top