[ back to Tom 7 Radar ]

n
e
r
d

c
i
t
y
JavaScript rant (26 Jul 2009 at 14:38)
A friend posted some casual nonsense about how JavaScript is "elegant" and exposing the masses to functional programming with its "lexically scoped" closures on Facebook last week. I was sitting on the bus to the airport so I wrote this response, which I now realize is way too long to fit in Facebook miniboxes, so this seems like my next best bet. Surely skippable for non programming-language nerds. (Various general-interest travel report info coming up in a post soon.)

 clip 'n save
Re: "elegant": I think you are crazy. (I program in Javascript all the time professionally and wrote a compiler to it for my dissertation.) It has numerous design blunders at its core, like requiring everything to be accessible through string-based names and hashes at runtime, except when very sophisticated compilers can tell that very simple code does not require this; its notion that erroneous expressions should continue execution by propagating "undefined" instead of telling the programmer; treating everything as an object in a misguided attempt to achieve uniformity but then requiring a whole host of exceptions and special cases because of course, functions are actually different from integers after all. Of course I disagree on its matters of taste regarding types, and balk at ideas like in v5 of adding "yield" (a complicated beast instead of something actually simple and well-understood like continuations), or whatever. But I don't need to defer to taste to make my point.

Just open up the (massive) ECMAscript definition. You'll witness that the language definition is literally the codification of the C program (see e.g. the 54-step description of the Array.prototype.splice function, filled with GOTOs and k++s on ECMA-262 p.95) that some Netscape engineers (possibly good hackers, but who certainly did not understand programming language design nor that their code was going to become forever entrenched in the tower of garbage we're now building the information age on) crapped out on a coffee binge to fix some demo script written by some other language-naive hacker which script they both basically agree should work because it seems natural or some such. Without any regard to language-wide implications. I've been on projects before that built languages that way so the symptoms are easy to recognize. Examples are everywhere: Automatic semicolon insertion? That as a result some productions in the grammar (e.g. x++) have special cases banning newlines between tokens? The inscrutable contextually-dependent semi-sameness of 0, null, false, undefined, 0.0, "", {}? That there are multiple internal intermediate values that are required for explaining the semantics of the language, but that cannot be expressed in the language? That its grammar is such that almost every phrase is defined with both regular and "NoIn" versions (e.g. BitwiseANDExpressionNoIn), the latter being identical but not containing the "in" keyword, so that they can explain the behavior of the parser they inherited (I can only imagine what it looks like)? That there is no actual character type, so strings are only usable as arrays of length 1 strings (themselves arrays of length 1 strings, i.e., infinite objects)? Not to mention all the crazy stuff you can do by modifying built-in prototypes (I called a function and now every array has a 4th element of your choosing?) or properties of the global object like undefined and null (Why aren't they just literals like true and false?).

And what about this gem (ECMA-262, p.121):
"15.9.2.1 Date ([ year [, month [, date [, hours [, minutes [, seconds [, ms ]]]]]]])

All of the arguments are optional; any arguments supplied are accepted but are completely ignored. A string is created and returned as if by the expression (new Date ()).toString()."
Not even an explanation? Is this some kind of fucking joke??

At least p.139 cites its sources:
"Unlike other regular expression operators, there is no backtracking into a (?= form (this unusual behaviour is inherited from Perl)."


Re: "Lexical scope": my ass. I don't think there is a single thing in the language that is lexically scoped. There aren't even variables. My eyes glaze over when I try to understand the details, but roughly speaking, every "variable" is a property of some object, usually the activation of the function body you're currently evaluating. Like what do you think this code does?

function installHandlers() {
   for (var i = 0; i < 20; i++) {
     var elt = document.createElement('div');
     document.body.appendChild(elt);
     elt.innerHTML = i;
     elt.onclick = function() {
       alert('Clicked #' + elt.innerHTML);
     };
   }
}


You get 20 boxes with numbers, but if you click, the message always says #19. Why? The mention of elt in the function looks up the property called elt in the activation object for the call to installHandlers. There's just one: Even though I'm saying "var elt = ..." what that really means is find the property elt in the closest function scope and modify it to this new value. The var keyword has nothing to do with variable declaration, in other words. There are plenty of ways to write this code where you get the behavior seemingly intended by the above code (most involving introducing extra function definitions and calls so that you get new objects for them) and seasoned JavaScript programmers get along fine with it, but this isn't lexical scoping (it isn't even dynamic scoping!).
c
o
m
m
e
n
t
Jason Ganetsky (cpe-72-225-160-217.nyc.res.rr.com) – 07.27.09 01:13:46
The idea of every variable being a property of some object is exactly what I found very nice about the language. The notion that the global namespace is really just an object, every activation record is just an object, and every object is an object... is minimalistic. This makes Javascript a small language at its core. This is nicer than Scheme, where looking up a variable by name is done by one of two mechanisms... the variable is either lexically scoped, or is in the global "dynamic environment". Meaning, if the compiler comes across a reference to "x", and "x" has not been declared, it will emit code to look up "x" by name at runtime to find a (define x ...). I would say what Javascript did is unify Scheme's two mechanisms, AND prototype-based objects, in one fell swoop. Scope chains and prototype chains are pretty much the same thing.

var does have to do with variable declaration... if you omitted var, you would be putting elt into the global object instead of into the function's activation object. For the code that you wrote, you can use the new "let" keyword to make an activation object mid-function and get the behavior that you expect.

I think looking everything up by string is great for a dynamically typed language. It gives you flexibility. I don't think compilers have to be too complex to optimize that away.

Yes, I see there's a giant mess in the details of Javascript's specification, and the ECMAScript definition is like a big program. I would only hope that they fix this in Javascript 2.
c
o
m
m
e
n
t
Scott (ip70-179-94-234.dc.dc.cox.net) – 07.27.09 02:56:38
Wow. Pull no punches. I'm curious now if you're familiar with Lua. Lesser known for sure, but I've seen mention of it as a small, elegant language with some functional capabilities.

Where'd you fly?
c
o
m
m
e
n
t
Scott (ip70-179-94-234.dc.dc.cox.net) – 07.27.09 02:57:59
Oh, Zurich. That is what I get for not really reading your blog sometimes, but trying to post comments other times.
c
o
m
m
e
n
t
Anonymous (207.10.176.34) – 07.27.09 13:59:10
I can assure you that, with respect to my claims, these ugly details like the Date object and regular expressions are not what I'm calling elegant. I haven't pored over the specification, and I'm certainly grateful that other people have. I do think Brendan Eich is a pretty smart guy, and understands language design (maybe not with the same exact values you hold). He certainly does regret the bad parts of Javascript, and no one is claiming that Javascript is anywhere near perfect. Also, I'm not judging it in terms of how easy it is to write proofs about, or to judge the correctness of a compiler... although these are ultimately important.

I'd like to focus some more on what I started talking about. With regards to your closure example: that's a canned argument you could apply to any language with closures that's not default immutable. Languages where names are bound to mutable variables tend to function the same way as Javascript. Scheme, Python, Perl, etc all behave this way. Java awkwardly "fixes" this by requiring you to declare any closed-over variable final. Take an ML program, make all variables refs, and it will behave the same way too.

All these dynamic languages look everything up by string, as well. The fact is, I think Javascript does these things better than Perl/Python/Ruby/PHP etc. And my point was that, instead of having a giant, messy object system, it has a small one that is flexible and easy to reason about. Javascript has first-class function support, and methods are really just properties in objects that point to closures... so this (and the pervasive use of closures in libraries like jQuery) is why I think Javascript has gotten millions of web developers, untrained in the art of programming, to think in a functional way.

But, ultimately, I don't think it's even close to the best language out there. Erlang, with all it's flaws, is flat-out better than Javascript in my book (and probably yours too).

You should avoid calling people you argue with "crazy". I think the CMU PL department has gotten a reputation for behavior like that.
c
o
m
m
e
n
t
Jason Ganetsky (207.10.176.34) – 07.27.09 13:59:47
That last post was me.
c
o
m
m
e
n
t
matus (cse-dhcp-10-158.ucsd.edu) – 07.27.09 15:59:53
does all this dynamic web shit still use xmlhttprequest? hahaha what an abomination.

also A+ on the pwnage
c
o
m
m
e
n
t
✄✄✄✄✄✄✄✄✄✄✄✄... (cse-dhcp-10-158.ucsd.edu) – 07.27.09 16:02:53
✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄
✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄
✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄
✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄
✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄✄
c
o
m
m
e
n
t
Ezra (209-6-216-58.c3-0.smr-ubr1.sbo-smr.ma.cable.rcn.com) – 07.27.09 22:41:08
This one really galls me: 'The inscrutable contextually-dependent semi-sameness of 0, null, false, undefined, 0.0, "", {}?'

The scoping is broken but I've learned to work around it, like a battered wife.

The semi-sameness I can't deal with.
c
o
m
m
e
n
t
Anonymous (linux3.gp.cs.cmu.edu) – 07.30.09 04:53:12
You can look at the spec of any halfway popular language or platform and find ugly warts. Few people have the motivation, ability, time or luxury to write something like the definition of Standard ML, itself not without flaws, not to mention that those with an abundance of these characteristics still tend to produce crap (cf. monad transformers).

The claim---that you might not actually be making but that seems apparent from your rant---that elegance is impossible in Javascript is not justified by the numerous, granted, deficiencies of the language.

And I hope you guys at google who know what's what will be more involved in the next iteration of Javascript instead of leaving it again to unschooled hackers and standards committee suits to fuck up.
c
o
m
m
e
n
t
William (pool-68-162-171-5.pitt.east.verizon.net) – 07.30.09 14:43:57
I implemented yield-based iterator-generators in SML/nj using call/cc. Now that we have a precise specification -- in terms of a well-defined host language -- there's nothing to fear! :)

exception No_more
type 'a iterator = unit -> 'a (* raises No_more *)
val withYield : (('a -> unit) -> 'b) -> 'a iterator
c
o
m
m
e
n
t
jonas (dsl51b61952.pool.t-online.hu) – 07.31.09 05:41:38
Jason Ganetsky: agreed, don't forget Scheme, it too has all lexical variables mutable.
c
o
m
m
e
n
t
Tom 7 (h-69-3-248-152.phlapafg.dynamic.covad.net) – 08.02.09 11:14:58

J: Re: "crazy", you're overreacting here. This is a personal blog post in response to a Facebook status message, not some an ad hominem attack in an academic capacity. You'll notice I called your remark "casual" and did not even mention who you are, because the post was not about attacking you personally. The point is to write a fun critique of JavaScript and maybe start a good-natured flame over it. I'm proud to reinforce CMU's reputation of being vigorous defenders of good taste and making passionate arguments for the things we care about, backed up by technical reasoning and made entertaining with hyperbole.

Re: "Take an ML program, make all variables refs, and it will behave the same way too." This isn't true. Concretely,

(*
(ML does not have a DOM interface. Let's pretend:)
type element
createElement : unit -> element
propertyString : string -> element -> string ref
propertyHandler : string -> element -> (unit -> unit) ref
alert : string -> unit
*)

fun installHandlers () =
let
val i = ref 0
fun loop () =
if !i < 20
then let
val elt = ref (createElement())
in
propertyString "innerHTML" (!elt) := Int.toString (!i);
propertyHandler "onclick" (!elt) :=
(fn () =>
alert (!(propertyString "innerHTML" (!elt))));
i := !i + 1;
loop ()
end
else ()
in
loop ()
end

I'm trying not to be too snarky in the code about "make all variables references" because there are several variables here (e.g., the functions) for which it would be so completely awkward and useless to make references. This is also a silly way to write ML (looping by mutating a ref cell) and the code is very ugly as a result, but using something like tabulate or even Util.for might obscure the point. This code does not replicate the behavior in JavaScript. Why would it? Notice that elt is just a variable bound to a ref cell; we only read from it and in fact it would be easy to optimize away that ref from this program. It does nothing except make the program more roundabout.


If what you really meant to argue was that JavaScript could be made into a small dynamic language based around hash tables, by lancing all its boils and throwing out most of its baggage, then I do not disagree. That it would be elegant would be mostly a matter of taste then. It would certainly not be efficient. (I don't know where you get the idea that it's easy to compile it?) I think in large serious application development, programmers would still impose type regimes checked by frontends/compilers (as they often do now), because it is so easy to make costly mistakes otherwise. Personally I don't see what the point would be even of idealized JavaScript. IMO the language's only positive quality is that it is linked into the DOM and is ubiquitous on an important platform (web). If we were to make incompatible changes, we might as well replace the whole thing with something that better suits the purposes to which it is put.
c
o
m
m
e
n
t
Tom 7 (h-69-3-248-152.phlapafg.dynamic.covad.net) – 08.02.09 12:06:56
I guess I can blame only myself that the code in the previous post is not indented.

Anon: It's sure true that there's a lot of crap out there. This is why I refer to it as the "tower of garbage". Just because it is doesn't mean that it ought. I think the Definition of Standard ML stands as a good example of what is possible if you think and plan very carefully and actually design something rather than accrete features and bug compatibilities. It does have warts, but they are really pretty minor compared to the abominations found in the depictions of JavaScript, C++, or even C (this one I actually think is a decent and clean language, just way overused). There are a number of ongoing projects at CMU and elsewhere to figure out how to set the bar even higher, by creating exquisitely detailed descriptions of languages that automatically lead to reference implementations, and that allow for machine-checkable proofs of properties (and therefore freedom from certain kinds of mistakes).

Let me also say that my pedigree suggests a certain impracticality to my thinking, so I want to be clear: My first love is using computers to do cool things, and I think that the tower of garbage, however smelly and unstable, really is pretty impressive. It keeps getting taller. I live in it, indeed. One of the things that the bearded and austere programming language community has not figured out how to do is to make their work appeal to garbage architects. In my modern cynical viewpoint I think this is because we actually lack some important quality that is necessary for success in the weird software social ecosystem. (cf. the famous "Worse is Better" argument, but I don't think that's it. I think it's more like "contempt".) I really wish I could figure it out, because it's very sad to me to see great ideas wasted (in computing and elsewhere) because they are unable to penetrate. It's never too late: there are lots of plausible strategies for retrofitting the tower with some nicer parts, they just need cooperation.

I don't think I was claiming what you think I might have been ("that elegance is impossible in JavaScript"), but let me clarify. I think JavaScript the language itself is clearly inelegant. There are lots of deep reasons (I listed a few in the opening of my rant), and I take some cheap shots, but the cheap shots are really just examples among hundreds. I don't think it's fair to consider idealized JavaScript with warts removed (it's not clear to what extent that's possible while retaining its nature) when evaluating "JavaScript is elegant". Elegance is a broad quality.

However, I definitely think it's possible to write an elegant program in almost any language, including JavaScript. (I think I've written a lot of nice JavaScript code.) An example that's close to my heart is the 2006 ICFP programming contest that we ran. In it we created five or so programming languages that were explicitly designed to be ridiculous and broken, where the challenge of the contest was to program in these languages despite their deficiencies. It was really remarkable (though not that surprising) that several of the best teams wrote really "good" programs in these languages, like programs that embodied the spirit of the language, and that struck me as elegant. My favorite example was probably in the Balance language, which had a preposterous four-instruction vocabulary, each of which carried out multiple operations simultaneously (a yin and yang to "help" the programmer achieve "balance"), like when you add it always simultaneously subtracts some related quantities. The goal was to write programs (with really simple specifications, like "halt without crashing") that worked around this annoying "feature". The contest-winning team, Team Smartass (from the Goog) had an implementation of multiplication that struck me as really elegant; it was only a few instructions long and it actually *used* the simultaneous add/subtract behavior in a natural way rather than working around it. (They thought I had set this up on purpose, but really it was 100% their cleverness.) This fact is one of the main reasons I still find it fun to use computers despite really feeling like there's so much crap around. I don't totally understand the tower of garbage, but I do know that one of our most effective coping strategies is magnificent concrete pours of hermetic abstractions that contain the smell beneath and allow us to build still yet higher. Abstraction is what allows us to contain our vertigo. Only when I contemplate the whole, as a result of someone casually describing it as "elegant", do I need to feel that unsettling sensation. The dizziness can cause rants and/or vomit.
c
o
m
m
e
n
t
Donna (c-71-199-114-80.hsd1.pa.comcast.net) – 08.02.09 13:36:45
Tom: "I really wish I could figure it out, because it's very sad to me to see great ideas wasted (in computing and elsewhere) because they are unable to penetrate."

Agreed.

I think your comment about "contempt" was right-on, and perhaps also the refusal to acknowledge the main point in the "worse is better" argument.

I think what the PL community (in general) sorely lacks is collaboration with other sub-disciplines, such as software engineering (yes, I know what you think of that...), HCI, etc. Figuring out all these formal properties is indeed interesting and necessary, but without someone to pick up these ideas and turn them into something closer to might possible be consumable by "the masses," then the research will continue to stay on the dusty bookshelf.

The situation is particularly unfortunate at CMU, where there are great researchers in both software engineering and HCI, for instance. This culture of contempt for anything "inelegant" leads to myopia and ultimately hurts the stated research goal.

Now, Tom, what I like about your thesis is that you were practical as well as theoretical. In particular, you considered domains *other* than program analysis tools and compilers. :) I wonder if your experience with the "tower of garbage" helped here.

c
o
m
m
e
n
t
Anonymous (pool-68-162-144-150.pitt.east.verizon.net) – 08.02.09 14:32:26
Much or all of SE "research" is conducted with a studious ignorance of the theoretical foundations of the programming because, well, to do otherwise would be for the subject to go away, and we can't have that.

And notice that systems researchers have nothing whatsoever to do with SE either. I would say that they have even greater contempt for the "field" than do PL researchers, but that's just my opinion.

SE is all about trying to be relevant by accepting the status quo and papering over technical errors by erecting huge social and management structures designed to obscure them. It's doomed.

And never once have I seen anything beautiful or elegant emerge from SE. If something isn't beautiful, if there's no creative insight, then why bother with it?
c
o
m
m
e
n
t
Donna (c-71-199-114-80.hsd1.pa.comcast.net) – 08.02.09 16:52:03
Anon (do I know you?),

You seem to be making broad, sweeping generalizations while exhibiting what I can only describe as a "studious ignorance" of the field. ;) One of the first papers about information hiding was Parnas's seminal paper--and, guess what--it was a software engineering paper. Before you say that he wasn't the first to discover this concept, I'd like to point out that even PL researchers cite that paper (though not as often as they should, I think).

Several SE researchers that I know personally have a quite solid grasp of the theoretical foundations. They aren't ignoring them, they are simply pointing out that there are design tradeoffs.

If SE research is doomed, why is it having more immediate impact?

You seem to be equating "beauty" with "creative insight." I would agree, if a particular piece of research has neither, then, yes, there isn't much point. But, the seminal works in SE, and those that are highly regarded 5 or 10 years after-the-fact, do indeed have creative insight.

The "crap to not-crap" ratio may very well be higher in SE than in other fields, but I would argue that the "elgegant-but-useless to useful" ratio in PL is also a little too high for my taste.
p
o
s
t

a

c
o
m
m
e
n
t
[ Tom 7 Radar  •  Tom 7 on Google+  •  on Twitter  •  on Facebook ]