However, macros for javascript are being worked on. sweet.js is coming along really well, and just needs to continue ironing out bugs and maturing. http://sweetjs.org/ I believe that it could have a profound effect on JavaScript, such as parsing selector string at expand time.
sweet.js figured out how to do that in javascript, so we have full syntax-case macros just as easily.
In Groovy, for example, you have the equivalent of macros in the form of AST Transformations †, that look just like Java annotations, but can actually convert the code their are applied to (or, more specifically, the AST node) and transform it into something else at compile time. Writing AST Transformations in Groovy is not as smooth as writing macros in Lisp, as you have to deal with the AST nodes as objects (there are DSLs for this fortunately), instead of using the same language syntax directly, but they provide awesome metaprogramming capabilities as well. The Groovy standard library includes some very useful AST Transformations and frameworks like Grails use them to a great extent too.
So, i think that, even though macros (or equivalent code transformations) are not very accessible to the average programmer if the language does not have homoiconicity, they can be of great value for library writers. As the linked article shows, they could be used to make something that looks like jQuery but generates much more efficient code :D
† http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AS...
Also, wouldn't it be more accurate for the selector testing to actually test against Sizzle[1]?
Other features aren't even present in jQuery, such as templating, and so I'm not sure why you'd even compare that. Yes people can and do use templates with jQuery, but that's an implementation detail and is not a concern of the library itself; jQuery does not coerce or force you to use a slow templating system, and most any good templating system will also have a compilation step that is run at build-time. So yeah, you can take some ugly userland jQuery example code and make specific code that is faster..
No, currently Dommy has a smaller feature set that we think covers a majority of use cases, while maintaining reasonable browser support. Our general philosophy is to add functionality as we need it or others request it. I don't think this makes the comparison invalid. We're comparing the general use cases (selectors, basic dom manipulation, etc.) that any DOM library should have. Can you point out a specific comparison that doesn't apply because of api differences or browser support?
> wouldn't it be more accurate for the selector testing to actually test against Sizzle[1]?
Part of the point is to show that you can achieve the same elegant chaining-like syntax as jQuery without wrapping selections, so maintaining the wrapped jQuery selectors are important for comparison.
> Other features aren't even present in jQuery, such as templating, and so I'm not sure why you'd even compare that.
The point of the templating comparison is to show that macros can provide a significant performance boost while maintaining a sane syntax.
I'm also curious how well Dommy would perform in the 'real world'; seeing as everything is compiled down to plain JS, then the divide between library and implementation is removed. jQuery is a larger download hit on the first visit, but if it's already in cache (perhaps before they even reach your site) then the only code required to be downloaded is your app's specific implementation.
In the Dommy example for the templates, the jQuery code is 10 lines -- when formatted like generated.js (the equivalent Dommy code) and removing 2 unnecessary variable declarations. By contrast, generated.js is around 60 lines (giving you a few on account that there's some empty else-statements...). I know minification can do wonders, but the jQuery implementation is clearly going to be much fewer bytes. At what point does it eclipse the size of the jQuery lib itself? I guess that's up to usage.
If your library is the implementation, then it'd seem like you'd have a lot more data being sent over the wire, and likely more often as well on account of any changes to the Dommy which alters the output will have an effect on the cached files for each of them where that functionality was used. On the other hand, updating jQuery means only the 1 file has to be re-downloaded -- and not every userland implementation which uses the API.
I am just getting started with Clojure/CS and am evaluating the different options.
http://pedestal.io/ http://keminglabs.com/c2/ https://github.com/drcode/webfui http://ganelon.tomeklipski.com/
If it ends being javascript string in the ends, how is it 7x faster (or whatever number)? I mean, sure the compiler could optimize a part of my code, but other javascript compiler could do it to.. right?
Although I find the Clojure example very sexy, I don't like how the examples tries to compare to contrived Javascript. I.e. I've been coding javascript for a couple years and I've never used jQuery "sort/filter/slice". But more importantly, it uses pre-defined function in Dommy but not in javascript. For instance:
(->> (sel [:ul.my-list :li])
(sort-by #(-> % (sel :input.last-name) .-value))
This uses sort-by where there's: function(a, b) {
return (
$(a).find('input.last-name').val()
.localeCompare(
$(b).find('input.last-name').val()
)
);
in Javascript.. Obviously, I can say: $('ul.my-list li').sortBy(function(x) { return x.attr('last-name'); }
My point isn't that much that jQuery is longer/shorter, but mostly that if two examples in two different languages are to be compared, it makes sense to use the same function.. where in this case sort-by is a high-level sort.>> One is the loneliest number
It's not just "1" or "more than one", it's also zero. Iterating on a list makes it such that you can freely think in a high-level way about the operation and not about the exceptional cases. I.e. $('.blabla').hide(); It Just Works.
>> (mapv #(add-class! % :first-ten-adults)))
Yes, of course you can use map.. but using $('..').addClass('first-ten-adults') makes it so much easier to deal with, instead of knowing what works on one object, what works on multiple objects, what will throw an error if there's nothing, etc.
Meh.
I think Dommy is a great library but the author didn't do a great job at explaining why it rocks. I guess attacking a very popular language with its most popular library doesn't help :p
Re one/map: you can still do operations on sets of 0, 1, or any number of elements, without knowing how many, by always doing map. There's nothing to keep track of, everything always only works on one object, so you're explicit about whether you're operating on exactly one object, or whether you don't care how many objects you're operating on. The latter is just as convenient as jQuery; the former is safer and deliberate. In jQuery, on the other hand, you have to keep track of what works on one object and what works on multiple objects: .text() and .text('a string') are asymmetrical, for example.
I'm not saying that all sluggish performance in web apps is caused by inefficient DOM manipulations, but having a DRY and efficient way to express DOM manipulations could help a lot in that regard =D
edit: WebFUI[1] is one clojurescript project trying to provide a pure interface for dom manipulation; there are others.
We use standard manipulation.
As a general rule, mutable API's tend to outperform immutable ones.
Seems to be pretty mature, there are apps in App Store written in it, and there are companies, using it for their front-end (i.e. Prismatic :)).
> Does the compiler eliminate unused code from the final output?
That's done by Google Closure Compiler in advanced mode.
I also want to mention webfui (https://github.com/drcode/webfui). It is authored by Conrad Barski, who also wrote Land of Lisp. He gave a nice talk about it at the Chicago Clojure meetup group a few months back. He is a fellow hacker news user so I figured he deserved a shout out.
So it continues to only be the ideal choice for pet projects.