I'll sue you if you use my common-sense JavaScript tests
groups.google.com
groups.google.com
We were the target of a highly superficial "review" by him soon after Cappuccino was made public: http://groups.google.com/group/comp.lang.javascript/msg/1799...
(for the record, YES and NO are there for compatibility with Objective-C, and we benchmarked the math functions, used in graphics routines which needed to be highly optimized, and found a significant performance improvement, in IE if I remember correctly, by aliasing them to eliminate the Math object property lookups)
I'm far too much of a generalist to consider myself a JavaScript expert. However, even I can pick out a number of items in his lib that shouldn't have been handled the way they are:
- He declares $ in a global context without first checking for its existence;
- He uses RegExp objects constantly -- in 50 different places in his full "mylib.js" -- including in cases where a simple indexOf would be better, and, best yet, he doesn't bother to cache them in any of the dozen or so cases that I examined. Wasn't that one of his criticisms of someone else's code?
- His treatment of camelCase is truly embarrassing, relying on an ugly RegExp every time it's called. Try something like this instead:
_camelCases = {width:'width', height:'height'};
_camelCaser = function (p) {
return typeof _camelCases[p] != 'undefined' ? _camelCases[p] : _camelCases[p] = p.replace(/\-(.)/g, function(x, y){return y.toUpperCase()});
}
There, now you only need to camelCase the property for anything once. JavaScript's object handling makes caching this kind of stuff soooo easy. And, if you do have to have a camelCasing function, try to do it with as little overhead as possible -- use the tools that JavaScript gives you, instead of capturing the string parts in a match and then .join()ing them and all that other nonsense.His library doesn't demonstrate any of the kind of specialized language knowledge that he accuses other library developers of lacking, and it has at least some of the same weaknesses that he criticizes others' works for.
- minifying and gzipping the javascript files is considered standard practice now, and the code I posted as-is is actually shorter than David Marks' case [* I lied! It's not, by 100 chars. Even shortening the object references kept it a bit longer. I don't think this defeats the rest of my points though.]. It could further be shortened, a lot -- to the point that for all practical purposes it's as small as a non-memoizing version.
- I tend to use a camelCaser in much more than simple animation loops -- any time for example that the style attributes for any element are referenced. i.e., it qualifies as an inner-most function.
- Although it's true that in animation loops you just have to beat the frame rate, let's keep in mind that there are a wide variety of processors and systems in use, and not everyone is using the latest dual-core Intel system with 3 gigs of RAM.
As a point of personal style, I much prefer to take the shortest, fastest, least-resource-intensive path for any given task, even if it's not strictly necessary to do so. As an end-user, I'm disgusted beyond description with the mindset that has become so prevalent among programmers, where efficiency is something that should be solved in hardware. It's absolutely frustrating that there are sites where the programmers have made so many concessions to speed in the name of rapid development that I can't even get the site to load in a few seconds on a 1.5 ghz G4.
So, yes, you're right, but I think the bit from David Marks' code is still naive and still does not make best use of the language:
camelize = function(name) {
var m = name.match(reCamel);
return (m)?([m[1], m[2].toUpperCase(), m[3]].join('')):name;
};You had a good point about total size of the code being downloaded, so I went back and tried to see if I could shrink mine a bit without pulling any dirty tricks -- when I realized that a chunk of his code is 'hidden' in the reference to the regular expression object he's created elsewhere.
With that added, and matching my code style to his, my version is less than 20 characters longer than his -- and that's without doing anything sneaky.
But, maybe there just isn't a big difference in speed? So, I set up a quick test. Again, I wanted to be fair, so I could understand what was going on. The two tests are identical, I didn't advantage mine in any way or disadvantage his.
The results?
Given a list of 11 valid CSS properties to "camelize", some with dashes and some without, my code can camelize the set 20 times over in 1 to 2 milliseconds.
The non-memoizing version can camelize the set 20 times over in ... 1034 to 1212 milliseconds.
That's a significant difference, IMO.
Tested on Firefox 3.5/Mac.
...all that said, thanks for reminding me about function size and download speed. I try to keep my own library at under 1000 source lines of code, but there are definitely some areas where I can sacrifice a few lines to lose a chunk of text. (Like, wrapping "typeof object != 'undefined'" into an "undef(object)" function.)
Yes, memorizing camelized styles would be more efficient, but then the library doesn't deal with hyphenated ones in the first place. It's used in exactly two places and neither has anything to do with styles. Instead, it deals with (very rarely encountered) hyphenated _attributes_ (you should have guessed, or God forbid read the code you were criticizing).
And aren't you just picking one (tiny) bit that you can sort of relate to and mouthing off without any real clue about what you are talking about? <whine>And why didn't _you_ report it to the author to be constructive, build a community, etc. What an awful jerk!</whine>
BTW, your version will blow up in Safari 2 due to the function passed to replace. Good luck with that!
People tend to measure the "success" of their libraries or other code based upon whether or not it accomplishes their goals. If your goal was to simply build a set of abstractions, continue support for ancient browsers, and ensure that it continues to work for future browsers, then you've accomplished it and that's great.
However, you fail then to recognize the goals of other frameworks and libraries which differ from your own. That is, they sacrifice compatibility with very old browsers for the sake of improved performance and support for newer browsers; or they sacrifice strict correctness for improved rates of development; or they sacrifice other aspects of Javascript-specific techniques for the sake of readability or establishing patterns familiar to novice programmers.
The authors of other frameworks can no more be criticized by you for failing to meet your goals, than we could criticize your library for failing to meet our goals.
Indeed, you're correct that I did not read every one of your more than 9,000 lines of code (almost 330K!) for the complete library. Rather, given your penchant for reading a few lines of some framework, critiquing them, and then declaring them to be no longer worth your time -- I thought I'd try the same.
...Actually, I'm being needlessly rude there. The truth is, I did attempt to review portions of code inasmuch as I had time for. Much of it was simply not notable; I picked out the camelization for one point because I had been tuning my own just a few nights ago.
Thanks (seriously) for pointing out the Safari 2 incompatibility. I'll consider whether adding support for Safari 2 is worth re-working that line. (Probably not, but maybe.)
We could continue to dicker back and forth on the relative merits of one bit of JavaScript versus another, but I'd rather keep working on mine, other people would rather start writing their own obvious unit tests, and you would hopefully rather update your library or something.
jQuery is _downstream_ from My Library. If you go back a couple of years in CLJ, you'll find that I'm the one who tirelessly argued with Resig and co. until they dumped UA sniffing. And yeah, they copy code and ideas from me to this day. But that is _not_ why I point out the botched implementations of those (and other) ideas. I point them out because the code is bullshit.
All of that stuff about improved development time and readability and support for whatever browsers misses the mark (no pun intended) as well.
* The others are not more readable * The others are not more advanced (despite my Write Once, Do Nothing strategy). * The others are not more compatible (not even close) * The others do not perform better * The others do not have better support (the authors are too confused about what they are writing or copying)
The only thing the others have going for them is that they actually (disingenuously) market their projects. I don't have the time or need to do so.
The library is only 330K if you select _everything_ in the builder, which is the equivalent of jQuery + 100 plug-ins. It's got easily the best Flash module, a unique audio module, "sidebar" widgets, a CSS selector query engine, animations (including DirectX), etc., etc. And it all works going back a decade or so and continues to work going forward (I rarely touch it). And contrary to the laughable comment I saw in here, it perfectly suitable for use in the "Real World". That expression is so tired (and meaningless usually) it is in a coma. I sometimes wonder if the people who write things like "Real World" and "snark" actually talk like that. :)
I don't know what you mean by "simply not notable". On technical, usability and compatibility merits, it's the most notable blob of cross-browser JS ever published. But I never really called attention to it other than as a way for others (e.g. Resig) to learn. When it came out, all of the frameworks were doing crap like this:-
if (isIE6) { } else if (isSafari || isIE8) }
...and about to collapse under the weight of all of these flaky forks. You can't maintain BS like that.
Read your history, you will get an extreme sense of Deja Vu (and perhaps a laugh or two).
http://groups.google.com/group/comp.lang.javascript/browse_t...
And I never said anything about Resig co-opting my "obvious unit tests". There's a lot more than tests on that page. Nor do I have to update My Library (that's the main point of feature testing).
Here's some more reading for you:-
http://peter.michaux.ca/articles/feature-detection-state-of-...
http://thinkweb2.com/projects/prototype/
Seriously, you just might learn something. This is why I speak loudly (and carry a big script). :) Otherwise, all of you "hackers" might have remained oblivious to the fact that jQuery, Prototype, MooTools, etc. are Z-grade scripts at best. It's not always a poor use of the language, but more often a poor grasp of cross-browser scripting techniques, which leads to endless Beta tests, wholesale substitutions, etc. It's a relatively hard way to go, despite what the commercials (blog posts) tell you. ;)
I'm sure there're people out there that enjoy comp.lang.javascript too.
For some reason (which I could make guesses at) Usenet attracts this type of kookery, and when kooks gather, they tend to create this appearance that people actually value their rants and conspiracies.
As a result, you get the perceived 'Erik is god' views of comp.lang.lisp, whereas people that try to read, or contribute, consider(ed) him and his ilk as a deterrent to useful discussion.
Their popularity outside the community seems to reflect the popularity of the community itself, which in turn reflects how much it does for the world at large and how similar its values are to the "mainstream". I'm kinda curious why such cult followings develop, but it seems to be a near-universal feature of communities of sufficient size (basically anything over Dunbar's number, where not all members know all other members). I've got a few hypotheses on this but no answers.
That's quite a brave statement from David Mark.
FWIW, I also view js libraries with skepticism. I'm not convinced they're a net gain for the web. (I'm talking about general purpose libs. UI libs obviously provide value).
There's this misconception that working with the DOM is hard, or can't be done in a cross browser way without bolting on a big js lib.
Even something as simple as a closure is routinely packaged up in a js lib as .bind() why??? Add to that the fact they usually do silly things like convert arguments to an Array etc just to slow you down some more.
When you see news stories like "js lib X latest release is 5 times as fast as previous version!" You should not think 'wow that's great'. You should think 'jesus christ how could they have written it so slow to start with? How do I know they've written it properly this time? Time to stop using js lib X'
It solves problems I don't have. I don't need to lookup elements in the dom, because I put them there. I already know where they are.
I don't need a slow .bind() method - I know how to write closures.
Look at one of the top news items - jQuery plugin 'behavior'. It just doesn't make any sense.
Look at some of the source code. For example .addClass(). It's the most general you could imagine - can take a list of classes, or a function. Yet I'm betting most of the time it's being called with a single class to add. There's a lot of wasted checks and effort in there. It's checking the type, it's splitting the string on " ", it's checking to see the class isn't already listed etc etc
Also everything is assuming it's operating on a list of elements - cue wasteful for loops when they're not needed.
So, when you do the seemingly simple
$('#myelement').addClass("foo");
it'll be cycling through the array of elements of length 1, splitting 'foo' on spaces, checking if 'foo' is a function, etc etc etc etcThose are precious wasted cycles. And for what? so you can write:
$('#myelement').addClass("foo");
instead of: // I already have a js ref to myElement thanks,
// and know myElement doesn't already have 'foo' in className
myElement.className+=" foo";
</rant>I believe jQuery's strength is that it allows you to accomplish things neatly without needing to know the sins and virtues of Javascript....
The point is that there are plenty of both.
Therefore, I'm sad to admit that, in this case, he almost has a point. The use of attr('height') to mean not the height attribute in the DOM but as an alias for height() smells wrong to me. However, it's clear that he has absolutely no intention of becoming a productive contributor to jQuery or helping in any way.
By contrast, let's take a minute to appreciate this Matt Kruse fellow. He has apparently strong objections to something in jQuery's design and is taking it to John Resig. He seems ready to engage in a real dialogue. The end result? He probably ends up a little happier and jQuery ends up a little better.
The real question is: how can we have more Matt Kruses and fewer David Marks in the world? Do the David Marks of world drive off the Matt Kruses? (I think they almost certainly do.) Why are there so many sociopathic personalities in circles such as this, and how do we mitigate the damage they cause?
He does, I agree, almost have a point. However, his lack of respect for those who spend time and energy contributing to these projects could (and will likely) drive away many useful contributors. "Feeding the trolls" is a dangerous game, much more so than avoiding the advice of a few David Marks.
The problem with this strategy lies in the fact that most open-source projects are large, open communities, where experts in a particular area useful to that project are likely not to be ignored. John Resig's response to the situation (in which he condemns the entire comp.lang.javascript usenet group) seems an extreme (but perhaps appropriate) response to this -- he's sending a very strong message to those who contribute to jQuery: "no more feeding David Mark".
(I would also agree that this Matt Kruse fellow seems to be going about things in an excellent sort of way. His response to Resig < http://groups.google.com/group/jquery-dev/msg/e93f9484cd5246... > was, in my opinion, spot on)
See http://www.reddit.com/r/programming/comments/7vul9/some_tech... http://www.reddit.com/r/programming/comments/8ndyw/jquerys_l...
Resig +1 Mark -1
window.blah === undefined
and require the more verbose equivalent I've seen pushed on c.l.j:
typeof window.blah === "undefined"
There's simply no market left for this sort of paleo-Javascript.
if (undefined = someVar) {...}
The typeof check cannot be broken in this way.
15.1.1.3 undefined The value of undefined is undefined (see 8.1). This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.
It's true that it can be broken today by unintentional assignment at the global scope, but you're basically skating on thin ice as soon as you redefine undefined or one of the many built-in global object types or global mutable values anyways (Array, Element, Object, NaN for example). Ditto for adding anything to Object.prototype.
I wouldn't blame a framework for wanting to place at least some burden on the user to follow a set of basic guidelines to ensure the library functions correctly. Ideally you'd ship your development-time, unminified version of the library with a bunch of startup-time assertions to ensure that the user isn't accidentally walking over core JS objects.
Alternatively, you could workaround the mutable nature of some of the globals by defining your own in-scope. When these values are eventually made read-only, these assignments should become no-ops:
var undefined = void 0; var NaN = 0/0; var Infinity = 1/0;
This is comment is rambling a bit, but I think I can justify the position that at least some of the recommended practices of the c.l.j folk are wordy, unnecessary and out-dated.
I think he just has angry-hyperactively-perfectionist-armchair-developer syndrome.
Case in point: where is his brilliant contribution to the JavaScript ecosystem?
The scary thing is that I don't think he actually is a troll. I could be wrong, though.
The bad side: he consistently antagonises people, has what seems to be a personal vendetta against jQuery and declines to publish useful, constructive critiques, instead posting ill-formatted, snide rants dressed up as code reviews on comp.lang.javascript. His behaviour towards John Resig has resulted in Resig claiming to have turned his back entirely on comp.lang.javascript, which is great shame because I think there is a lot he could learn there to improve jQuery. If David Mark's attacks are turning people away from comp.lang.javascript, then that is unfortunate because he is by no means the only expert on there and others experts on there will have less of an audience for their insightful posts.
I think it's a bold claim to say that David's understanding of the DOM is "significantly deeper" than John's. Especially considering that the DOM is not a particularly complex set of APIs.
One can only hope that he does actually improve Dojo, instead of destroy their community or credibility with his rants.
Not really most libraries use feature testing, especially jQuery and John advocates feature testing in quite a few of his writings.
Instead of detecting which browser you are using based on which features you support, the script should check to see if the features it wants to use exist, and if so use them.
So, instead of:
var isIE = !!document.all;
function doSomething()
{
if (isIE) document.all.whatever();
}
You do: if (document.all)
{
function doSomething()
{
document.all.whatever();
}
}
Even closer to the point, he means that these are both bad form: var isIE = navigator.userAgent.ssubstr...;
var isIE = !!document.all;However, I have a challenge for you: calculate the browser window's width in pixels, before the page is done loading, and return the correct value without doing any browser sniffing.
Enjoy. :-)
There is some shred of validity to them.
However, most JS coders are too busy using jQuery or Prototype or something to Get Their Project Done and then move on to the next thing to be bothered by this guy.
It's not all that usable ITRW.
Many programming mailing lists I've been on ended up acquiring somebody like this, at which point I usually have to unsubscribe in order to resist the temptation to get into pointless flamewars.
...Not that this should be reduced to a popularity contest.
Still no idea who he is.
Or, to put it in more childish terms, "if you're so smart, let's see you do it."
I think John is being pretty pragmatic though just to exorcise the whole deal and attempt to enforce a clean room environment for the affected code branches.
I'd like to see him write cross browser key-event handling code without doing UA sniffing. Honestly, I would like that. He committed an attempt to a branch of Dojo but it's not in service and doesn't actually work.
http://groups.google.com/group/comp.lang.javascript/browse_t...
"Cappuccino. That's something built on top of Sproutcore, right? No need to get any deeper than that."
Of course, Cappuccino isn't built on Sproutcore, but even if it was this sentence illustrates the fact that David has long ago made decisions about what he perceives to be the state of javascript frameworks, and isn't interested in anything other than those opinions, however baseless those opinions may be.
I noticed in several parts in his response, he's trying to claim credit for aspects of jQuery's development -- something that I think most people would find patently ridiculous. Given David's recent threats, if I were Resig, I'd be tempted to start using the word "defamation" and tell David to put up some evidence or shut up.
Fortunately, I'm sure Resig's more level-headed.
Also, it's spelled Cappuccino. And since David's superficial review contained virtually nothing of substance, there isn't much to objectively respond to.
Example:
<script src = "Frameworks/Objective-J/ObjectiveJ.js" type = "text/javascript"></script>
> Nice markup.
Yes, one file in 280 Slides (not Cappuccino) has spaces between the attribute, equals sign, and quote. We must be incompetent. > Yeah, I guess "false" is harder on the fingers.
Or, maybe, we're going for an easier transition for people from an Objective-C background... with (new prototype_bug())
member = true;
> Ugh.
How insightful. Hilariously enough, this is actually doing real feature detection to detect a real bug in real browsers. > I've seen enough.
So, in other words, he made no substantive evaluation. If you ask us questions, and aren't a dick about it, we're more than happy to give answers. We readily admit our own faults, and we're vocal about what our framework is not designed to do.Why pull things out of context and not provide a reference to the original?
You complain about the tone of his posts (someone called it snarky) and then go on to post your own snarky comments, why?
Still, I think there's a difference between responding to an unprovoked attack thread, and starting one in the first place. In any case, we'd all be better off with a little less sarcasm and a lot more substance in this discussion, and for that I apologize.
It's absolutely fine to have an automated tool to enforce style guidelines. But code which disagrees with that tool isn't necessarily bad. We have published style guidelines for our project, and they differ from Doug's. Those projects may very well have their own published guidelines.
Doug has never said that code which fails JSLint is obviously retarded, or written by fools. He's never publicly insulted individuals because he didn't agree with their design decisions, or written mailing list posts saying someone has "never written a competent script in his life."
So, what's your point?
The point being that I'm tired of reading responses that only focus on an insulting comment a poster makes in order to dismiss all valid technical criticism.
If you include insults, purely stylistic criticism, and valid technical criticism all in an orgy of excited and angry words, people aren't going to take the time to dissect the actually interesting bits.
And, let's not forget, you're the one who claimed that jQuery and Prototype fail horribly on JSLint without providing any information on the actual errors, so the burden to prove they are not just style errors is still on you.