to learn jQuery if already using prototype

P

Peter Michaux

There is nothing obvious about this problem in the linked thread.

It seems that IE6 performs very well when one level of object
namespacing is used. These results in favor of IE and a level of
object namespacing seem too good to be true. I've tried slight
variations on the tests below with similar results.

TEST ONE --------------------------------------------------------
430 ms FF2
430 ms IE6

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test 1</title>
</head>
<body>

<script type="text/javascript">

var symbols = []
for (var i=0; i<2000; i++) {
var name = 'sym' + i;
symbols.push(name)
this[name] = function() {};
}

var tic = (new Date());
for (var i=0; i<20; i++) {
for (var j=0, jlen=symbols.length; j<jlen; j++) {
this[symbols[j]]();
}
}
document.write((new Date()).getTime() - (tic).getTime());

</script>

</body>
</html>


TEST TWO ---------------------------------------------------------
440 ms FF2
120 ms IE6 <------ Wow!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test 2</title>
</head>
<body>

<script type="text/javascript">

var symbols = []
var namespace = {};
for (var i=0; i<2000; i++) {
var name = 'sym' + i;
symbols.push(name)
namespace[name] = function() {};
}

var tic = (new Date());
for (var i=0; i<20; i++) {
for (var j=0, jlen=symbols.length; j<jlen; j++) {
namespace[symbols[j]]();
}
}
document.write((new Date()).getTime() - (tic).getTime());

</script>

</body>
</html>
 
V

VK

It seems that IE6 performs very well when one level of object
namespacing is used. These results in favor of IE and a level of
object namespacing seem too good to be true. I've tried slight
variations on the tests below with similar results.

TEST ONE --------------------------------------------------------
430 ms FF2
430 ms IE6

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test 1</title>
</head>
<body>

<script type="text/javascript">

var symbols = []
for (var i=0; i<2000; i++) {
var name = 'sym' + i;
symbols.push(name)
this[name] = function() {};
}

var tic = (new Date());
for (var i=0; i<20; i++) {
for (var j=0, jlen=symbols.length; j<jlen; j++) {
this[symbols[j]]();
}
}
document.write((new Date()).getTime() - (tic).getTime());

</script>

</body>
</html>

TEST TWO ---------------------------------------------------------
440 ms FF2
120 ms IE6 <------ Wow!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test 2</title>
</head>
<body>

<script type="text/javascript">

var symbols = []
var namespace = {};
for (var i=0; i<2000; i++) {
var name = 'sym' + i;
symbols.push(name)
namespace[name] = function() {};
}

var tic = (new Date());
for (var i=0; i<20; i++) {
for (var j=0, jlen=symbols.length; j<jlen; j++) {
namespace[symbols[j]]();
}
}
document.write((new Date()).getTime() - (tic).getTime());

</script>

</body>
</html>

The results are amazing :) but not for the reason you are possibly
thinking of. It doesn't matter if one has top level or level down
functions. The "slowdown key" is in using window host object in DispID
resolution. I know that you are - as many - have been zombificated by
"window = this = Global". It is not true in overall and it is
especially wrong for IE that has to be ready to accommodate and
intercommunicate two completely different languages: JScript and
VBScript. Here window acts as a mediator level between two Globals of
two engines and any intensive usage of it for DispID resolution
decreases hits the performance with a big strength. In your second
sample replace
namespace[symbols[j]]();
with
this.namespace[symbols[j]]();
and "enjoy" the result.

Also try this for fun: (just don't take it as an eval promo, please) :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Test 1</title>
</head>
<body>

<script type="text/javascript">
for (var i=0; i<2000; i++) {
var name = 'n' + i;
eval(name+'=new Function');
}

var tic = (new Date());

for (var i=0; i<2000; i++) {
var name = 'n' + i;
eval(name+'()');
}
document.write((new Date()).getTime() - (tic).getTime());

</script>

</body>
</html>
 
R

RobG

Possibly we are talking about different OOP ideas. The one proposed in
the conventional CS departments assumes classes created on the base of
other classes (superclasses) where the choice of the superclass to
extend is based on the required minimum of augmentation to receive new
class with needed features.

I was just trying to point out that that isn't necessarily a
consequence of OO programming. Similar dependencies can be created in
a library of functions that aren't object oriented where there are
dependencies of functions based on lower (or higher, depending on your
perspective) tiers of functions, which is essential what a class
hierarchy is.

This way the modularity of a particular
class depends solely and exclusively on the position of such class in
the inheritance chain. If some class extends Object directly then it
is rather simple to include it directly in some other block. With a
class being on the top or even middle of the chain its inclusion also
requires the inclusion of all underlaying chain segment. Because no
educated guess can be a priori made about the position of the class X
in library Y, OO modularity overall is low - yet its maintainability
is high, as I said.

"Maintainability" is a double edged sword in this case. It becomes
very difficult to modify a higher level class if there are many, many
sub-classes based on it (as you said your self in regard to backwards
compatibility).
It is possible to imagine (and to make) a library
where each and every class directly extends Object, no matter how
close some classes would be to each other. Just don't call it OO based
library then.

I think the term "object based" fits javascript much better.

"The common knowledge basics mentioning" would be more appropriate :)
Again - unless we are talking about different OO ideas.

No, I was just in a crappy mood. :)

[...]
Of course. Say - just a small sample - make a library where $
identifier is used for your own purposes not related with DOM ID
lookup. Now try to sell it without fixing it. Report the results. ;-)

You might have chosen a better example, I wouldn't use $ in any part
of an identifier name in a javascript program as the projects I work
on use a large numbers of server-generated identifiers like
xyz00$pppMmmmm and xyz00$UserStatus1$FullName.

It also reminds me of other programming environments where $ has a
particular meaning. As far as I know, the usage stems from using $
(elementID) clientside and $elementID serverside. It may have seemed
cool at the time, but could be classed as a newbie mistake that never
got fixed because a whole bunch of other noobs picked up on it as
beeing cool.
 
R

Richard Cornford

Andrew said:
How is that different?

I will take that as a "yes". It does bring in to question the worth of
my saying anything at all.
You're hyper-parsing my statements. I think the response the OP
got _isn't constructive_ clearly you disagree.

If someone is going to make a mistake then being told that it is a
mistake certainly can be regarded as constructive, even if not as
constructive as being told why it may be a mistake.
I think some of
the criticism of Prototype that occurs in this newsgroup _isn't
constructive_, but some _is_. I am saying that I will disregard
things that I don't feel are constructive. Therefore there is no
"requirement" of any sort. Jesus.

But anyone then asserting that, for example, the best way forward with
Prototype.js would be to delete it and start again from scratch will be
disregarded even if they think that advice is constructive (and it is
virtually the only way that it would be possible to correct the mistake
of violating the language's specification's injunction against using the
'$' symbol as the initial character in Identifiers except when they were
machine generated).
Nothing. Go eat a taco if you like.

You wrote "... they obviously need to do more persuading", but not there
appears to be no obvious necessity here.
Somewhere along the way I got you mixed up with Thomas. For that
I apologize.


I'm not arguing whether it's true or not. If I say "Martin
Scorsese can't direct for shit," I expect people around me to
look at me funny, because whether my statement is true or not
it goes against consensus. Therefore I might feel a burden to
_elaborate_.

But would you still feel the need to elaborate in the company of people
who shared that opinion?
And you seem to say that a small handful of silly choices in
a framework mean the entire thing is worthless.

No, I am saying that when the people who designed frameworks/libraries
and the like are demonstrating fundamental shortfalls in the
understanding of the language they are using then the consequences of
that evident ignorance are likely to also manifest themselves in the
overall design of those frameworks/libraries. That is, they are
indicative of the consequences of design decisions (which may themselves
be regarded as largely subjective) being as uninformed (by both
knowledge and experience) and so that the whole of which they are a part
being in some sense 'junk'.
No, his assessment is a matter of taste. The part that
connects his memory and his opinion.

For some reason my memory connects the notion of genocide with "really
very bad", but I suppose that is just a matter of taste.
We disagree on the degree to which this is important. I think
we've gone as far as we can on this point.
Probably.



That's a very vague statement. A few examples would be greatly
appreciated.

Examples of what precisely?
The words "slow," "anything," and "complex" are
relative to the individual,

Only to a limited degree. They are more relative to the words "fast"
"nothing" and "simple", respectively.
and obviously must be taken into
account when making a technology decision. jQuery's central
API focus - fetching nodes by CSS selector - means that a
line of jQuery code is often much slower than the equivalent,
non-framework-aided code.

Yes, occasionally someone shows up here and complains that attempting to
sort 10,000 table rows is unacceptably slow. To which there is little
choice but to say that that is how it is and you deal with that by
designing the need to sort 10,000 table rows out of the system (a
response that is generally not taken as being constructive, despite
being the best advice going). I have seen people complaining that
JQuery's performance is unacceptable with as few as 400 table rows to
sort.
Many people use it anyway because
they deem it to be worth the trade-off.

To judge a trade-off it is necessary to know and understand the
alternatives. I suspect that the majority using these things are doing
so in order that they don't have to learn the alternatives and so carry
on using them regardless not as a result of assessing a trade-off but
rather because they have no real alternative.

Apparently I need to stop using sarcasm. I also need to stop
speaking abstractly, aside from basic declaratives (e.g.,
"Your tone is too harsh."). You are reading the most literal
of meanings into every single word I write.

Reading literally. Literally?
Case in point. I don't know why you think I was trying to
censor conversation in the first place.

I did not think you were trying to censor anything (beyond those things
that you will 'brush off' as a result of their not being 'constructive',
but that is only going to impact on you so it does not really count). I
observed that there were considerable advantages in the exchange of
ideas being censorship free, despite the fact that the consequences of
that may include the odd post here or there being a knee-jerk
generalisation rather than a reasoned argument.
My point is that
I can't (and don't want to) censor anything.

Beyond those things that you will 'brush off' as a result of their not
being 'constructive'.
Needlessly argumentative and willfully dense to the point
I'm making.

Try making your point in as many words.

Again, argumentative. The fact it's a bad name for a library
(which I agree with) is unrelated to the point I am making.

I thought that the point you were making was that attempting to look up
"prototype" in the archives resulted in such a food of responses that
fining the substance that (may or may not) inform the 'junk' assessment
was not practical.
This is like saying I ought to read the entirety of Donald Knuth's
published works before I write a simple algorithm.

More like saying that you maybe ought to read at least one book by
Donald Knuth before putting yourself forward as an arbiter of algorithm
correctness.
You may be right in your "bet," but that's not how a user in
need of help is going to _behave_, so what's the user of
pretending otherwise?

What has a "user" to do with anything? The purpose of this group is not
to help individuals with their problems (to the extent that that happens
at all it is no more than a side effect of the group). The group exists
to allow its participants to discuss javascript, and the reason that its
participants want to discuss javascript is to improve their own
understanding of the subject. All the question asking and answering is
just a convenient mechanism for getting the ball rolling (and carries on
because the vast majority of questions get reasonable good answers
(eventually)).
First of all: we don't sniff the UA string to detect IE.

So you are not continuing to argue about "technically baseless" or
"ineffective"? Certainly you are not pointing out the location of the
technical basses for UA string based browser sniffing for all to see.
We sniff
to distinguish between other browsers (e.g., between Gecko and
WebKit),

And for two years I operated IE 6 with the word 'Gecko' in its UA header
(in order to render MSDN usable), and at no point during that time was I
in violation of HTTP 1.1.
but we use a different heuristic for IE.

The test you are using for IE is an object inference test along the
following lines of:-


IE: !!(window.attachEvent && !window.opera),


- and that betrays its own folly. The reason for including the -
!window.opera - bit that Opera's creators have seen expedience in
providing their browser with 'IE compatibility' features. The problem
with that is that the same rational that motivated Opera's creators may
influence the manufacturers of any other web browser. And so any browser
may potentially have an - attachEvent - method of the window object, and
in the even that any do they are unlikely to bother to implement a -
window.opera - object as well (because Opera compatibility is not going
to be a worthwhile path to pursue). Object inference may by a marginally
superior strategy to UA string based browser detection but it is
predicated upon such a detailed and broad knowledge of web browser
object models that the only way of seeing it as a valid strategy would
be to pretend that there were only 3 or 4 browsers in existence.
Second: your gripe seems to be that we use any
heuristic at all - that it's not possible to detect
differences in UAs with 100% accuracy.


You make it sound like browsers can be differentiated with some degree
of accuracy. User Agent string based browser sniffing cannot
differentiate between browsers that use the same sequence of characters
in their User Agent headers, and cannot handle unexpected header content
(despite there being no technical grounds for expecting anything
specific in any such header). Object inference is only ever as good as
the direct (and detailed) knowledge of browser object models, and a more
detailed knowledge than the majority of those attempting it demonstrate
in the tests they devise. And it suffers from necessitating much ongoing
code maintenance because knowledge of browser object models can only be
knowledge of existing browser object models, so not even including the
next version of any existing browser let alone any new browsers that may
come into existence.

History has already exposed the fact that object inference browser
detection sows the seeds of its own invalidity. It is no accident that
browsers have been observed that implement an - ActiveXObject - global
function even though they were designed to be cross-OS (and you cannot
instantiate an ActiveX object on non-Windows OSs). It was a direct
consequence of javascript authors attempting to use the existence of
that object to infer that a browser was IE, and so turn otherwise
perfectly usable browsers into apparently non-functional browsers. The
manufacturers of those apparently non-functional browsers then become
well motivated to spoof enough of the IE object model to fool such
tests.
99.99% accuracy is good enough for me. I'm not insisting
that you must agree;

That may be acceptable if it could be known to be 99.99% (or even
something approaching it), but that is no more than a guess, and a
very flawed guess at that. Where would that number come from, if
not derived from web browser usage statistics? Even disregarding
the inherent issues with statistics gathering over HTTP (the
unknowable and probably inconsistent influence intermediate caches
being just one) and the self-biasing nature of browser usage
statistics, the browser identification issue remains. Browser
usage statistics use User Agent string based browser sniffing
(with a few throwing in some rudimentary object inference
testing). Which means that if you used browser usage statistics
to justify your guess of 99.99% accuracy of your browser
identification techniques you would be implying that those browser
usage statistics were, more or less, accurate despite their
employing pretty much the same techniques. That is, the accuracy
of the techniques you use would be being justified by the
assumption that those same techniques were accurate. But if
they are not accurate then there is nothing to justify your
claims of 99.99% accuracy. Making that a somewhat circular
argument.
I'm only asking not to be regarded as a savage.

You will have to make that particular appeal to a different audience.
No, I would rely on the unit tests to demonstrate a consistent
behavior. It doesn't give me 100% certainty because I can't
test every string on earth. (In this case, obviously, we didn't
test enough strings.)

More like you did not write the unit test such that they exposed to code
to input that was likely to be miss-handled. But that was just the
consequence of the experience shortfall that mentioned previously (and
you deny exists at all).
Again: someone else did notice it. But it did go unfixed for
about a year, and I find that disappointing and unusual. We
agree on the former but not the latter.


Again, you're being oddly argumentative. I don't care how it
sounds to you.

And I would rather not see this type of BS at all (and even if nothing
else is "constantly" certainly is BS).
Are you sure?

Yes, the Titanic's problems were in the fundamental design not how shiny
the trimmings were.
The bug submission screen has a gigantic text box in which
you can make any sort of condescending judgment you like.
How can you resist?

Very easily.

Richard.
 
R

Richard Cornford

dhtml said:
I really didn't want to be goaded into postup a dumb and
dumber competition with other people's code, but you've left
me with not very good choices.

You had a choice.
YUI has some pretty bad/obvious bugs in crucial places.
augmentObject, hasOwnProperty. Dom.contains:-

hasOwnProperty: function(o, prop) {
if (Object.prototype.hasOwnProperty) {
return o.hasOwnProperty(prop);
}

return !YAHOO.lang.isUndefined(o[prop]) &&
o.constructor.prototype[prop] !== o[prop];
},

- Which will throw errors in IE when - o - is a host
object and return wrong results in Opera when - o - is
window. augmentObject:-

So? Does the documentation propose that this method is objects other
than native ECMAScript objects?
augmentObject: function(r, s) {
if (!s||!r) {
throw new Error("Absorb failed, verify dependencies.");
}
var a=arguments, i, p, override=a[2];
if (override && override!==true) { // only absorb the
specified properties

Why do you find it so difficult to cope with posting code that is not
mangled by line wrapping?
for (i=2; i<a.length; i=i+1) {
r[a] = s[a];
}
} else { // take everything, overwriting only if the
third parameter is true
for (p in s) {
if (override || !r[p]) {
r[p] = s[p];
}
}

YAHOO.lang._IEEnumFix(r, s);
}
},


It is questionable strategy to do object augmentation
on the prototype chain of the supplier.


So a "questionable strategy" not a bug?
It would be better to use hasOwnProperty to
filter the stuff in the supplier's prototype chain out.

No, it would not. It may, under some circumstances, be better, but it
also may not be; it depends on what outcome you are after.
Next, if the receiver has a property p with a false-ish
value, then the ovveride flag is irrelevant.

That may be how the code was programmed, but what makes it a bug?
Dojo calls object augmentation "extend" which to me seems
to be misleading.

Misleading code may not be great, much as obscure code may not be great,
but where are the bugs you spoke of?
isAncestor: function(haystack, needle) {
haystack = Y.Dom.get(haystack);
needle = Y.Dom.get(needle);

if (!haystack || !needle) {
return false;
}

if (haystack.contains && needle.nodeType && !isSafari)
{ // safari contains is broken
YAHOO.log('isAncestor returning ' +
haystack.contains(needle), 'info', 'Dom');
return haystack.contains(needle);
}
else if ( haystack.compareDocumentPosition &&
needle.nodeType ) {
YAHOO.log('isAncestor returning ' + !!
(haystack.compareDocumentPosition(needle) & 16), 'info', 'Dom');
return !!(haystack.compareDocumentPosition(needle)
& 16);
} else if (needle.nodeType) {
// fallback to crawling up (safari)
return !!this.getAncestorBy(needle, function(el) {
return el == haystack;
});
}
YAHOO.log('isAncestor failed; most likely needle is
not an HTMLElement', 'error', 'Dom');
return false;
}

This would return inconsistent results, depending on the browser.
For example:
YAHOO.util.Dom.isAncestor(document.body, document.body);

What does the documentation have to say about the expected arguments?
Though the last is not as obvious a mistake as the others.

So there was no evidence of any bugs in the others and this one is less
obvious than they were?
There are considerably questionable practices in the Event
library.

What have "questionable practices" got to do with your suggestion that
you may be presenting "pretty bad/obvious bugs in crucial places"?
The connection manager is horribly designed. The fact that
it attempts to do form serialization within iteself, is
just a horrible decision. If the author had been forced
to write a test for that, he'd probably have moved that
form serialization code somewhere else, to make it easier
to test (easier coverage verification).

So you don't see the difference between writing code that logically
cannot be executed and your opinions about how things should be
designed? Unfortunately your not perceiving that distinction goes quite
some way towards bring into question your opinions on how code should be
designed.
[snip]
And where those
authors are part of a collective they don't speak for the
knowledge of the specific author responsible but instead
indicate the level of understanding of the _most_
knowledgeable person involved.

This can lead to blocking code reviews and scape goating.

What "can lead to ..."?
With a test driven approach, the only thing to blame is the
process, and that's fixable (besides the fact that the test
never has any hard feelings).

A test driven approach helps nothing when the people designing those
tests are not capable of stressing their code to the point of showing
how were and why it falls over.
Without tests, you get things like blood commits and code
freezes. Some libraries actually do code freezes. And they
have at least one expert. And they have bugs. Dumb ones.

So if YUI is not the library with these bugs (just "questionable
practices", in your opinion) why aren't you naming it here?
It addresses the problem that was demonstrated in your
example. It does not, however, take into consideration
the possibility that - this - could contain * any * other
entities.

No, but it was not coded to do that.
If the need to handle - &quot; - or & (which is also
'&') got added in later, they'd need to be reviewed by the
one, sole expert, to make sure the person who wrote the
amending code didn't make a rookie mistake. A test could
clearly prove it worked.
Obviously.

var s = "&quot;".replace(/&quot;/g, '"');

So the fix addresses only one concern.

Yes, it addresses the thing that stops the pair of encoding/decoding
methods being symmetrical.
another consideration is that String.prototype.escapeHTML
should be stable, but if there's a bug, and dependencies on
that bug, then the fixing of the bug becomes complicated.
In may very well be the case that some novice programmer used
escapeHTML, found that it didn't work right, made some
adjustments in his implementation to compensate for that bug.
In essence, his implementation is now depending on that bug.
This is where I see adding things to built-in prototypes to
be risky.

That is a truly lousy argument for not augmenting built-in prototypes,
as it is just as true for any aspect of any public API in any
general-purpose library.
If the programmer had made a method, then that method
could always be deprecated in a future release, if found
to be problematic.

What is to stop a library that augments the built-in prototypes from
deprecating the methods it adds to the prototype?
So, to sum it up, my recommentations:
1) write a test

A reasonable suggestion, but a little superficial. The assertion is that
there was a test for these methods, but that in itself did not expose
the issue.
2) don't put the methods on String.prototype because they
might change later.

You might as well say 'don't put methods anywhere as they might change
later'.
That was my first time writing an unescape function in
Javascript.

But you did have the advantage of knowing that there was something up
with the code as it had been written, which usually makes finding and
fixing an error easier.
I think I might have written one in Java several years ago
in a response filter exercise, though.

If I had to write something more comprehensive to account
for more entities, I'd probably consider looking into
inverting control to the browser's parser using a combination
of newDiv.innerHTML and newDiv.textContent|innerText

That is what Prototype.js's other versions of this method do (hence the
cross-browser inconsistencies as it means that those methods will
handle other entities where these version will not).
document.body.textContent = "&";
document.body.innerHTML; // &amp;

document.body.innerHTML = "&quot;"
document.body.textContent; // "

Obviously not using document.body, but a newly created node.
I would probably write some tests for that, including the
cases you posted, make sure they all fail, then write out
some code (the code could be changed in the future, since
there are tests).

A general entity encoding/decoding method is probably either over the
top or totally unnecessary for most real-world contexts.

Richard.
 
V

VK

But anyone then asserting that, for example, the best way forward with
Prototype.js would be to delete it and start again from scratch will be
disregarded even if they think that advice is constructive (and it is
virtually the only way that it would be possible to correct the mistake
of violating the language's specification's injunction against using the
'$' symbol as the initial character in Identifiers except when they were
machine generated).

So are you proposing to trash out a whole library because one of used
identifiers is _not suggested_ yet fully valid? IMO it is an act of
lunatism. Prototype.js has a number of its defaults - but making $
usage as the main reason to drop it makes the poster look ridiculous.
And the least I want to see in c.l.j. is _Richard Cornford_ looking
ridiculous or funny. Upset, sarcastic, nasty - any time, just please
don't make fun of yourself. Can you switch on some _substantional_
library criticism instead?
 
P

Peter Michaux

But anyone then asserting that, for example, the best way forward with
Prototype.js would be to delete it and start again from scratch will be
disregarded even if they think that advice is constructive (and it is
virtually the only way that it would be possible to correct the mistake
of violating the language's specification's injunction against using the
'$' symbol as the initial character in Identifiers except when they were
machine generated).

ES3 spec:

"The dollar sign is intended for use only in mechanically generated
code."

Both "intended" and "mechanically generated" make the sentence
ambiguous. It is only a recommendation at best.

Since ES is a spec that is based on existing implementations and
language use, I think the safe bet is that such a reservation about $
in identifiers will be removed when ES4 is published.

Peter
 
R

Richard Cornford

Peter said:
ES3 spec:

"The dollar sign is intended for use only in mechanically
generated code."

Both "intended" and "mechanically generated" make the sentence
ambiguous.

Not that ambiguous (and particularly with the word "only" in there).
That sentence explains why a character that really did not need to be in
the set of characters allowed in identifiers was included in that set.
It is only a recommendation at best.

Yet the reaction to an almost identical assertion about Java identifiers
in its specification results in Java programmers finding the idea of
using a $ symbol unthinkable; something that only complete novices and
armatures would do, and an error that would stamped out as soon as they
got into a professional context.
Since ES is a spec that is based on existing implementations
and language use, I think the safe bet is that such a reservation
about $ in identifiers will be removed when ES4 is published.

ES4 looks like it is going to be a serious (if predictable) mistake. How
much of a mistake will not be clear until there is a specification to
read.

Richard.
 
D

dhtml

You had a choice.

I made a choice.
YUI has some pretty bad/obvious bugs in crucial places.
augmentObject, hasOwnProperty. Dom.contains:-
hasOwnProperty: function(o, prop) {
if (Object.prototype.hasOwnProperty) {
return o.hasOwnProperty(prop);
}
return !YAHOO.lang.isUndefined(o[prop]) &&
o.constructor.prototype[prop] !== o[prop];
},
- Which will throw errors in IE when - o - is a host
object and return wrong results in Opera when - o - is
window. augmentObject:-

So? Does the documentation propose that this method is objects other
than native ECMAScript objects?

Doesn't say one way or the other. The author might not have been aware
of the differences with native vs host objects when he wrote:

if (Object.prototype.hasOwnProperty) {
return o.hasOwnProperty(prop);
}

It is unsafe to assume that just because
Object.prototype.hasOwnProperty, then o.hasOwnProperty will also be a
method.

It would be safer to use:
if (Object.prototype.hasOwnProperty) {
return Object.prototype.hasOwnProperty.call(o, prop);
}

And I'd really like to hear some others' have to say on that one.

But better yet:
if (typeof o.hasOwnProperty == "function") {
return o.hasOwnProperty(prop);
}

Because then there is no need to concern about what type of object is
passed. Is it a host object? A native Object? Who cares? As long as
that hasOwnProperty method is on the object that is passed in, then
try and use it. It's not 100% safe because it's entirely possible to
have the hasOwnProperty method shadowing the one on Object.prototype.

// Rediculous example.
liar.hasOwnProperty = function(p) { return !
Object.prototype.hasOwnProperty.call(this, p);};

liar.hasOwnProperty('hasOwnProperty'); // false.
liar.hasOwnProperty('toString'); // true.

It's a fairly common assumption that an object is an object. Mozilla
goes to some trouble to make Host objects work like an Object object.

In fact, speak of the Devil, I can look at Prototype right now and
find something that looks like it could potentially be augmenting a
Host object.

if (!Node.ELEMENT_NODE) {
// DOM level 2 ECMAScript Language Binding
Object.extend(Node, {

Some programmers write code that could potentially augment a Host
object. If augmentObject should never be used with a Host object, then
why not just call Object.prototype.hasOwnProperty.call(o, p), and
write a comment:-

// Not guaranteed to work on Host object, e.g. document.body.

augmentObject: function(r, s) {
if (!s||!r) {
throw new Error("Absorb failed, verify dependencies.");
}
var a=arguments, i, p, override=a[2];
if (override && override!==true) { // only absorb the
specified properties

Why do you find it so difficult to cope with posting code that is not
mangled by line wrapping?

I wasn't finding much difficulty in it, thanks.

j/k. Got your point.

for (i=2; i<a.length; i=i+1) {
r[a] = s[a];
}
} else { // take everything, overwriting only if the
third parameter is true
for (p in s) {
if (override || !r[p]) {


Here is the bug...................^

r[p] = s[p];
}
}
YAHOO.lang._IEEnumFix(r, s);
}
},
It is questionable strategy to do object augmentation
on the prototype chain of the supplier.

So a "questionable strategy" not a bug?

It is an unexpected behavior that can lead to unexpected consequences.
This should be clearly stated in the comments. It's something that the
user/client has to be aware of when using this method. There's no
discerning between shadowing and replacing, so it's entirely possible
that the receiver has a property - 'isOpen' - maybe in the prototype
chain, and the supplier has a property 'isOpen', but overrides is set
to false. The clients might expect receiver to get the supplier's
'isOpen' property, but if overrides is false, it won't happen. It will
only happen when overrides is true and 'isOpen' is not a value that
evaluates to false in a boolean context.

What's worse, when they go to the _IEEnumFix, the overrides flag is
omitted.

That's two bugs, and an unjustified, undocumented design (augmenting
on the prototype, which I think might be a careless error).

No, it would not. It may, under some circumstances, be better, but it
also may not be; it depends on what outcome you are after.

That is true. It would complicate things, though. That there is no
comment, example, or testcase, indicating this, I would say that it
seems likely to be a mistake.

I'll give this one an 'innocent' verdict, as the comment is too vague
at the intent of the code. I don't like that.

However, there is one more point to this complicated function:

* @param {String*|boolean} arguments zero or more properties
methods
* to augment the receiver with. If none specified,
everything
* in the supplier will be used unless it would
* overwrite an existing property in the receiver. If true
* is specified as the third parameter, all properties will
* be applied and will overwrite an existing property in
* the receiver

They've documented a name of an argument as -arguments-, which must be
a mistake, but whatever. It's arguments[2].

What if - r - has a property in it's prototype chain (with a true-ish
value)?

What does 'overwrite' mean? Replace or shadow? In the code, it seems
to mean either one, apparently.

That may be how the code was programmed, but what makes it a bug?

It is a bug because it does not do what it says. Specifically,

r = { a : 2 };
s = { a : 1 };

r.a will not be 1. It will stay as 2. (expected).
javascript:void((function(){ var r = {a:2}, s ={a:1} ;
YAHOO.lang.augmentObject(r, s); alert(r.a); })())

But,
r = { a : 0 };
s = { a : 1 };

Yahoo.lang.augmentObject(r, s);

r.a will be 1, even though override was not true. This is the bug.
javascript:void((function(){ var r = {a:0}, s ={a:1} ;
YAHOO.lang.augmentObject(r, s); alert(r.a); })())

+1 bug.

Another bug that I mentioned is that overrides is ignored in
_IEEnumFix. So, if you want to preserve Object.prototype.toString on
the receiver, then overrides would be false (default). Then if the
supplier has a toString or valueOf property in the prototype chain, it
gets copied over. But only in IE. Well, not always. If Opera (or any
other browser) is set to mask as IE, then that will be true in Opera.

Conservatively, that would be two bugs, given the bad browser
detection.

+2 bugs = 3 bugs.
Misleading code may not be great, much as obscure code may not be great,
but where are the bugs you spoke of?

I'm stopping with YUI right now.

I think I remember some weird results from dojo.coords method with a
scrolled window. Maybe I'll come back to that later.
What does the documentation have to say about the expected arguments?

" Determines whether an HTMLElement is an ancestor of another HTML
element in the DOM hierarchy."

I'm not certain now if you were unaware of this, or maybe you're
leading me down a blind alley, but the way contains() works in IE is
that if the argument is the same node, it returns true.

javascript:alert(YAHOO.util.Dom.isAncestor(document.body,
document.body));

true in IE, yet false in other browsers. That is a bug.

Because in IE, document.body.contains( document.body ) - is true.

+1 bug = 4 bugs.

So there was no evidence of any bugs in the others and this one is less
obvious than they were?

There are 4 bugs that you were unable to spot. I'm surprised.

The other bugs are more logical and javascript misunderstanding
errors. They have nothing to do with proprietary methods on host
objects (contains()). It is a forgivable mistake, and IMO the IE
contains() method result seems strange.

What have "questionable practices" got to do with your suggestion that
you may be presenting "pretty bad/obvious bugs in crucial places"?


So you don't see the difference between writing code that logically
cannot be executed and your opinions about how things should be
designed?

I see the difference.
Unfortunately your not perceiving that distinction goes quite
some way towards bring into question your opinions on how code should be
designed.

It absolutely does bring into question my opinion on how code should
be designed. I've gone into more detail.
[snip]
And where those
authors are part of a collective they don't speak for the
knowledge of the specific author responsible but instead
indicate the level of understanding of the _most_
knowledgeable person involved.
This can lead to blocking code reviews and scape goating.

What "can lead to ..."?

Having one expert and making the code go through that guy leads to
this type of situation. It also leads to that guy being in a position
that is likely going to give him the kind of power that might make
people not like to work with him, should he be careless or rude in his
judgement.

YUI does (or used to) do code freezes. This is inefficient because it
slows down changes that could have been safely made, had there been a
thorough test suite in place.
A test driven approach helps nothing when the people designing those
tests are not capable of stressing their code to the point of showing
how were and why it falls over.

It helps when they learn to look at the code in a less optimistic,
more critical way. That is part of testing. The code in question, the
escapeHTML, did not test the sad path. You seem to notice these things
a lot. Testing does encourage this type of mentality of "what if I do
XXX". Formal unit tests really do encourage looking at the code from
many angles, then testing all those angles, in one suite. It leads to
the discovery of bugs, which increases the code quality. It changes
the developer's mindframe to try and break the code. Testing makes
change a lot easier, too. This is an interesting blog entry that I
found: http://blog.objectmentor.com/articles/2007/10/20/architecture-is-a-second-order-effect

So if YUI is not the library with these bugs (just "questionable
practices", in your opinion) why aren't you naming it here?

1. 4 bugs here. And plenty more in the sourceforge bugtracker. (of
course, there are bugs that aren't bugs, but misunderstandings there,
and QA will file such "bugs", too). There's also an internal bugzilla
in Yahoo that is a little better, both the UI and the quality of bug
reports.

2. I did.

No, but it was not coded to do that.

It was not. The requirements change. I'm not advocating ambiguous
generality, but having a test ensures that the guy who goes and make
the change at the 11th hour (or maybe after happy hour) can push a
button and get a green or red light. It also clarifies the contract of
what the method does. It's DbC, in a separate layer: A test suite.

The escapeHTML function might want to consider the entity could be
&

Yes, it addresses the thing that stops the pair of encoding/decoding
methods being symmetrical.


That is a truly lousy argument for not augmenting built-in prototypes,
as it is just as true for any aspect of any public API in any
general-purpose library.


What is to stop a library that augments the built-in prototypes from
deprecating the methods it adds to the prototype?

They are deprecable, but. I'm going to have to come back to that.
A reasonable suggestion, but a little superficial. The assertion is that
there was a test for these methods, but that in itself did not expose
the issue.


You might as well say 'don't put methods anywhere as they might change
later'.

String should be more stable because it is built in. I'm not sure why
and I can't justify this, but something about it just doesn't feel
right. Now I could be really subjective and say that having
String.prototype.trim is justified because we all know what trim()
means and because trim is probably going into ES4, too (From memory,
but I might be wrong on that).

A method on something like Menu could be less stable. Menu wouldn't
have as many dependencies, other than implementation code. Changing
things that Menu depends on, however, would be a different story.
Changing the lower-level components (which might include String) --
things which might have other dependencies, such as Form, Tooltip,
Transport, would be harder to manage.
But you did have the advantage of knowing that there was something up
with the code as it had been written, which usually makes finding and
fixing an error easier.

Yep. It's looking at the code with a different mindset. Find the
error.
That is what Prototype.js's other versions of this method do (hence the
cross-browser  inconsistencies as it means that those methods will
handle other entities where these version will not).

I did look at it after posting on the thread here and noticed that,
too. That approach can have significantly inconsistent results, no
doubt, depending on the input and the browser.

[snip]

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

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top