On JS “Lambdas”

The ES working group is hard at work on “Harmony”, the goals of which are significantly more sane than previous attempts to build a new language from JavaScript. Namely, they’re being careful to be able to express things in new syntax based on old syntax. This is referred to as “de-sugaring”. Many new bits of syntax will be expressed in old syntax in a resulting spec, and so it will be with any new lambda syntax.

One of the things I find most persistently annoying about the language as we have it is the verbose and wordy way of saying “build me a new invokable thing”. Since JS builds dynamic scopes based on on functions, this is particularly annoying when writing event handlers, callbacks, and arguments to forEach and friends. Needless to say, these are the things we do all the time in JavaScript. If there was anything that deserved syntactic sugar, this is it.

This brings us to “lambdas”. Languages like Ruby have a great syntax for expressing “a thing you can invoke” in a terse way. Python has something along these lines based on the keyword lambda, but Guido insists on keeping them neutered based on (AFAICT from in-person discussions) a dislike of functional programming. Java is dangerously close to getting useful closures but it’s so syntactically handicapped that it’ll probably be another decade before the masses rebel and demand a terse way to say what they mean. Or maybe they’ll all have just defected to JRuby. For most of these languages, being able to say “here’s a new invokable thing” tersely is a Nice To Have feature. No real-world program will be slowed down by the size of a keyword. Indeed, Java makes you do so much work for the compiler that it’s practically taken as a badge of honor that you have to type it all out over and over and over.

JavaScript is different. Unlike nearly every other language, the terseness of JavaScript code is a key determinant in the performance of a web application. The bigger your scripts, the slower your app loads. It’s as simple as that.

It’s a crime, then, that we still have to type:

1
2
3
4
5
node.addEventListener("click", function(evt){ /* ... */ }, false);
 
// or
 
[/* ... */].forEach(function(i){ /* ... */ });

The syntax for “an anonymous invokable thing” should be a lot shorter given how much exercise it gets in the real world. What real-world script authors don’t need is something other than “a shorter way to say function“. Anything different than this isn’t strictly useful. Anything that requires you to use a more wordy syntax to name arguments is a failure, and anything that uses a name longer than the shortest possible thing just re-introduces that bug that needs fixing in the first place. There have been proposals at the ES working group to date regarding “lambdas” and most assume that they will be something that serves to make implementer’s roles easier when it comes to de-sugaring but fail in one of these ways. Folks who write actual scripts should start speaking up and telling the Harmony working group what needs to be clearly and un-ambiguiously said:

Don’t fuck with the semantics of function, just let me stop typing it so often

What might a better syntax for function look like?

The best that Erik and I could come up with that is relatively unambiguious for parsers, doesn’t introduce hard-to-type characters on certain keyboard layouts, and doesn’t mess with the semantics of function(){} is this:

1
2
3
4
5
6
7
8
9
10
11
12
// empty function body, zero arguments
var lambda = #(){ /*... */ };
 
// empty function body, arguments list elided away
var lambda = #{ /* ... */ };
 
// we can re-write the previous examples as:
node.addEventListener("click", #(evt){ /* ... */ }, false);
 
// and
 
[/* ... */].forEach(#(i){ /* ... */ });

The long history of the word “lambda” coupled with the different interpretations that various languages place on them make using the word “lambda” to say “a short name for something you can invoke” particularly loaded. Perhaps instead we should just call this new syntax that crams a lot of meaning into a short “keyword” something else entirely.

“Cramdas”, anyone?

Update: …and James Padolsey makes it so!.

24 Comments

  1. Posted May 20, 2009 at 11:20 am | Permalink

    This would be nice. Another nice way to shorten it would be to make return optional, so I could say #(n){n*n} for a lambda that takes one argument and squares it. So as in most functional languages, the value of the last expression evaluated would be the return value. As of now, this would return the useless void/undefined value. Any chance of adding this in as well, or would this be considered fucking with the semantics of function?

  2. Michael Peters
    Posted May 20, 2009 at 12:06 pm | Permalink

    Just for some more comparisons, Perl 5 just uses the keyword “sub”:

    my $lambda = sub { … }

    And Perl’s @_ array works just like Javascript’s arguments array.

    Perl 6 goes further and has “blocks” and “pointy blocks”:

    my $lambda = { … }
    my $lambda = -> $evt { … }

  3. RichB
    Posted May 20, 2009 at 12:38 pm | Permalink

    (a, b, c) => a+b+c;

    http://msdn.microsoft.com/en-us/library/bb397687.aspx

  4. Posted May 20, 2009 at 1:02 pm | Permalink

    You could also look at Smalltalk and see that for some uses of their lambdas (blocks), they actually just took “method names” (selectors). This let you flatten out your code, so all your callbacks weren’t neccessariy buried on other methods, but were plain old methods. And there’s obviously a slight performance penalty – someone has to lookup the function instead of just calling it.

    There’s another potential advantage to working this way; it avoids tight coupling of functions to their uses. If we ever get environments were reloading running code is possible and makes sense, have a layer of indirection between the functions will be nice. Otherwise all those folks with direct references to functions everywhere will find that those functions didn’t get updated on the reload. At least, until someone gives us #become: (not holding my breath on that one).

    Note that not all Smalltalk blocks were done this way, most weren’t, but some were; my memory is that the UI toolkit I used most used them. (CommonWidgets – the Smalltalk version of today’s SWT in Java, used them quite a bit)

  5. Posted May 20, 2009 at 4:09 pm | Permalink

    Very good and very timely post.

    Personally I want lambdas to achieve one goal: less typing. It means removing/bypassing both “function” and “return”, if possible. At least in simple cases.

    On ES4 mailing list several ideas were floated and one of them was to use a backslash:

    \(a, b){ a + b }

    or something like that.

    But anything that makes using lambdas easier would get my vote (I am not on the committee, so it is not counted officially).

  6. Posted May 20, 2009 at 4:23 pm | Permalink

    Really? The strings “return” and “function” are keeping us up at night? I grabbed a minified copy of jquery 1.2.6 that happened to be lying around, it weighed in at 31111 bytes. With a trivial search and replace I replaced “function” with “#” and “return” with “”, saving 71 bytes. Gzipped (like they’ll be when they’re served over HTTP to basically all browsers) the difference is 9 bytes.

    I don’t think that using the word “function” when declaring a function literal is a problem at all. It’s not quite as concise as the syntax for other literals like objects, strings, numbers and regular expressions, but functions are a little more complicated, having arguments, a body and (sadly) optionally a name.

    Perhaps it’s just time to get an editor with macros :)

  7. Posted May 20, 2009 at 4:32 pm | Permalink

    @Ian: to me it is not about the wire size (we have compression for that) but about cluttering the code with purely technical things making it less readable. I remember looking at some COBOL program: it could be read like a regular English text, yet I in order to grasp the idea of its algorithm I have to read pages and pages. That’s why operators rule over function calls, and lambda will rule too.

  8. Posted May 20, 2009 at 4:39 pm | Permalink

    Ian:

    Yes. Really.

    That is all.

  9. ben hockey
    Posted May 20, 2009 at 5:59 pm | Permalink

    how about fn(args){…} – if the semantics aren’t changing then fn would be a good choice since it is an already widely understood abbreviated form of function – just take a look at the lower left corner of your macbook ;)

    if the semantics were to change as far as return values then you could use fn or function depending on your want.

    it’s also a good way to abbreviate some of those dirty “effin” curse words you use alex! perhaps some of your frustration could be released through your thoughts when everytime you needed a lambda, you would think “effin” and then you might be able to maintain a PG rating on your blog :P

  10. Posted May 20, 2009 at 6:21 pm | Permalink

    ben:

    In the spirit of cathartic shortenings, may I suggest fu(ags){ ... }?

    ;-)

    Regards

  11. Posted May 20, 2009 at 10:53 pm | Permalink

    I think I’m on Ian’s side on this one. The function syntax seems properly expressive and makes it obvious what is happening in the code. I’ve never met anyone that was confused over what “function” meant. We really don’t need to be making JavaScript less understandable by creating shortcuts to common keywords just because we’re tired of typing them repeatedly. There’s something to be said for the readability and maintainability of JavaScript code written in the way that it is right now.

    In this case, “syntactic sugar” is really just “symbol replacement”, and that doesn’t seem to add much value on its own. Right now, “function” means “define a function”; I’m not sure how that could be any clearer.

  12. Posted May 20, 2009 at 11:04 pm | Permalink

    Nicholas:

    Language expressiveness is a balance between good Huffman coding (common stuff should be shorter than longer stuff) and descriptivness. This syntax is not “descriptive” in the sense that it doesn’t say “function”. It is, however, superior for all but the most trivial users of the language. At some point the word “function” actually begins to obscure the meaning of “I’m trying to create a closure as an argument”, which happens quite often.

    I understand the argument that says you might not need it, but improvements in turing-complete languages are rarely about “needs”.

    Regards

  13. Posted May 21, 2009 at 2:43 am | Permalink

    +1 for Paul Barry’s idea, adding implicit return to the short notation would be nice.

    Just don’t add it to the old functions for backward-compatibility.

  14. Shawn
    Posted May 21, 2009 at 10:53 am | Permalink

    @Ian: I grabbed the most recent minified version of jQuery and did a simple:

    sed -E -e ‘s/\s*function\s*/#/g’ -e ‘s/\s*return\s*//’

    …and got a savings of 4,220 bytes. So either the library grew an awful lot, or you were using a version that had been minified with something like packer using base62 encoding (which would have already removed nearly all uses of “function” and “return” at the cost of eval time). If the latter case is true, I don’t think that’s a very fair test, since the packed version is effectively doing (to a much greater extent!) what Alex is suggesting already.

    This isn’t to say that I think the size over the wire is really the most important consideration here (gzipping both versions reduces the difference to 339 bytes). The function(){} form in JS is as annoying as the array() literal in PHP.

    The minified version I used:
    http://code.google.com/p/jqueryjs/downloads/detail?name=jquery-1.3.2.min.js

    Packer:
    http://dean.edwards.name/packer/

  15. Posted May 21, 2009 at 12:30 pm | Permalink

    I am a big fan of Ruby’s block syntax. Just ” { … } ” and if you want arguments ” {|x,y| x + y } “. Very clean, and very readable.

    With that said, isnt there a javascript implementation of Ruby? HotRuby or something.

  16. LOL
    Posted May 21, 2009 at 12:54 pm | Permalink

    RIDICULOUS, get away from JavaScript thanks !

  17. Posted May 21, 2009 at 2:34 pm | Permalink

    Chris:

    I posted something not dissimilar to the ES lists some time ago, but it’s not clear to a native JS parser what the {| production should mean. As we were talking through it, Erik pointed out to me that the { ... } syntax (maddeningly) seems to be taken by a anonymous block syntax that many JS interpreters already support but which doesn’t actually *DO* anything. Grr.

    As a result, both of those syntaxes would involve lots of look-ahead, which some implementers are (apparently) loathe to contemplate.

    Regards

  18. Posted May 21, 2009 at 11:02 pm | Permalink

    If this ever makes it into EcmaScript, it would be great if it could avoid creating a new syntax and would instead adopt one that already exists in another “curly brace” language. I’m partial to the C# syntax for Lambdas myself.

  19. Posted May 22, 2009 at 8:24 am | Permalink

    Don’t GZip and text editor autocompletion features make this proposal moot?

  20. Posted May 22, 2009 at 10:48 am | Permalink

    What a mess. Less code is not easier to read. When a small amount of code contains the same functional logic as a large amount of code, the short code is *harder* to read.

    All languages have compilers to optimize their performance. Javascript has minifiers. I can have a large amount of human-readable source code while still sending a minimal amount of code to the browser. Please don’t make things more complicated than they should be.

  21. Posted May 22, 2009 at 4:42 pm | Permalink

    Leo:

    They address size-on-the wire. They don’t address human factors.

    Trav:

    I *wrote* one of those minifiers. You don’t need to lecture me on the topic of what is and isn’t effective in terms of reducing byte count ;-)

    As for readability, it’s a human-factors argument, and I’m arguing that seeing the word “function” all over the place really isn’t as clear as you think it is. Java tends to be difficult to comprehend for similar reasons…stuff gets munged into structures that don’t fit the intent as a side-effect of insufficient semantics married to bad syntax. JS is better on the functional side of things (the semantics are fine), but the sytnax is lousy. I’ll absolutely agree that a non-lame class composition system (traits, anyone?) would go a very long way to addressing some of the bigger issues in the language, but if the WG is going to chew of lambdas (and it looks like they are), we should propose something that doesn’t suck.

    We can absolutely make both sides of the language easier to use at the same time. There’s no either/or here.

    Regards

  22. Posted May 23, 2009 at 4:35 pm | Permalink

    @Leo: Both “GZip and text editor autocompletion features” do not help with understanding of the code in question. If we are to turn the functional programming in JavaScript up a notch, we will see nothing but “function” words everywhere. Excessive bloat does make code less comprehensive. OTOH we should balance the act trying not to turn programs into obfuscated riddles. That’s what Alex is talking about: no new rules, no new concepts, but more clarity by reducing unnecessary technicalities.

  23. Posted August 9, 2009 at 10:29 am | Permalink

    I like where you’re going with this, but I would vote against # as a symbol for function because its already used in so many other languages for ‘comment’.

  24. Posted August 9, 2009 at 11:04 am | Permalink

    Why not something like Functional JS:

    http://osteele.com/sources/javascript/functional/

    Implicit parameters, implicit returns, and a lots of handy functions taking advantage of short lambdas.

    It doesn’t do any DOM-y stuff by itself, but I’ve been using it along with Prototype for some pretty happy code.

4 Trackbacks

  1. […] comes from his proposal for JS Lambdas (or Cramdas). He continues: It’s a crime, then, that we still have to type: PLAIN TEXT […]

  2. […] on your imagination. Just as an example, I’ve implemented Alex’s (from Dojo) recent Cramdas idea; usable in the following way: <script type="application/javascript:cramdas"> var […]

  3. […] parece tener su Lambda: http://alex.dojotoolkit.org/2009/05/on-js-lambdas/. Share and […]

  4. […] is crying out for a way to write functions more tersely. I’ve added my suggestion to the debate, and was vaguely aware that Mozilla had implemented “function expressions”. It […]