FUTURE ALOOF

MIKEAL ROGERS

TC-thirty-what

This is a breakdown of all the ES-Harmony features I’ve paid enough attention in order to have a coherent opinion about them. An article of this size is a long time coming so…sorry for the length, buckle up, enjoy the ride, and watch the fireworks in the inevitable responses to it.

A very small lens

I don’t care about most things. When discussing JavaScript the language and what may happen to it I have only two concerns.

The first is that we enable applications to be written in the future that cannot be written today. JavaScript is a great language and between node.js and browsers, we’ve filled in the additional requirements for an application platform. But, there are still a few things we cannot build because of deficiencies in the language and base types provided by it. It’s important to clarify that I do not mean that we don’t have the sugar to make a task slightly more efficient, easier to read, or easier to type. Nobody ever said, “I couldn’t write my application because JavaScript doesn’t have generators,” but I myself have even said “We can’t write that database in pure JavaScript because we don’t have 64bit integers.”

My second concern is reducing confusion. We have three primary sources of confusion in the language: inconsistency, boiler plate, and flat out bugs. Two things that look identical are sometimes used differently. Code that is pervasive and identical is a great place for bugs to hide that you won’t find because you continually pass over the code blocks and new users are horribly confused about when and where issues occur. And the bugs, we all know the damn bugs, except new people who find them everyday and wonder why we chose this damn language.

Those are my only concerns. If you share them you’ll likely agree with me, if you don’t I guarantee you’ll hate everything I have to say. There may be, no, there has to be a lot I can’t see though this lens. This article is not the whole picture, but I can only write about what I care about.

function

A current source of confusion, especially for new users, is the many meanings of the keyword function.

The language says function might describe two things: 1) A function object executed by calling name() and 2) A constructor which can be used to instantiate a new object using prototypal inheritance by calling new Name(). The fact that these are the same thing and that you can forget the new keyword on a constructor and it won’t fail early is something even seasoned programmers trip on. It’s actually the policy in node.js that users do not call new on APIs in core and most modules follow the same patten of returning an instantiated object from a normal function to remove this confusion from taking place.

JavaScript’s dynamic nature, a dozen lines of code, and people’s unwillingness to surrender what they learned in their classes about Java have left us with a third meaning for function. In some cases, it may actually be a constructor for an object that uses classical inheritance. Well, isn’t that just great. For years now, if you named a constructor beginning in anything but an uppercase letter you would be brought outside and shot in the leg, so we have a somewhat obvious distinction between functions and constructors but we have no such indicator of what inheritance model that object might be using.

Alex might be surprised to find out that I’m actually not entirely opposed to the notion of a class keyword. I was actually a proponent of the thread Jeremy Ashkenas started as “Minimal Classes” which was basically the exact same pattern and semantics we have currently for classical inheritance but with a class keyword. In that form, I think it reduces confusion and is a good idea. I haven’t had time to watch what that proposal has become as it makes its way through committee. When it passes through the TC-39 meat-grinder I might actually hate it, but I don’t hate it on principal the way Alex assumes. Having two inheritance patterns in the language is confusing, but we already have that—calling out which one could actually help.

This is the part where I rant about generators.

I spent about 5 years writing lots of Python. In that time I can say that generators were always confusing to write, edit, and especially to debug. In Python, I found that they were mainly used to work around the terrible performance of Python function execution or because someone was just trying to be really clever (that person was routinely me).

I’ve heard several people say, “We need generators in node.” These people are rarely node programmers. Generators are used as a blocking return in Python and Ruby to iteratively return data being received by a file descriptor (socket, file, stdout/stderr, etc). We have something much better in node, we have Stream objects, and they work better than generators. The node community has built a huge amount of value on top of them that we could never have built on generators so even if generators make their way in to the language they’ll only be used for iterative computation tasks and never for IO.

Oh, and the best part, function gets to be another thing, because it wasn’t confusing enough already. NO, NO, NO, there’s a star after the function keyword, which somehow makes me more confused when I read it.

But wait, there’s more confusing function work. You can use that old, busted, 8 character (HOLY SHIT!) function keyword to define your functions or you can use the new hotness straight outta coffeescript (SUCKA!) arrow syntax functions (WHAT WHAT!).

While I can certainly remember many people asking me, “Why do I have to type 8 characters, why can’t I hit a key next to delete and then shift+. ?,” the worst part is not the syntax, it’s that arrow syntax functions actually have different semantics from regular functions. Arrow syntax functions scope this to the outer scope rather than the function scope.

All kidding aside, I do have to explain to a lot of new people how this is scoped. It is confusing, but not as confusing as having to explain that there are two sets of scoping rules for functions depending on the syntax you use.

This double semantic theme persists throughout the work in Harmony. TC-39 has decided that, unlike the failed ES4 effort, there will not be breaks in reverse incompatibility with ES5-strict, any code that runs today will run in this future Harmony mode. But, it’s perfectly fine to define grammar for Harmony that breaks in ES5-strict. This means that, among other things, features can only be added and none can be taken away or even changed.

We’re left with an effort that, by design, cannot fix bugs. Instead it can only add features that, when used, will work around our existing bugs but not save us from them. We’re left with the choice of either living with bugs or doubling semantics.

Obfuscation techniques

I’ve talked a lot about things that the language can do to confuse programmers but the biggest culprit of exaggerating that confusion is other programmers.

Going back to my Python days again, I can remember being enamored with the advanced features in the language. I learned how to use a new feature in the language every 4-6 months and it would infect all of my code. All of a sudden my loops were all replaced with big conditional generators and list comprehensions. There is a lot of incentive to do this. First off, you feel like a total badass. Second, you feel smarter than all your coworkers cause they don’t understand anything about what that code does. And finally, you’re using a feature that is, to some degree, optimized by the interpreter and better performance gives you warm & fuzzies.

What I was doing that whole time was making my code less readable, less maintainable, and terribly confusing not just for others but for myself when I would have to return to it. Offering features that enable obfuscation will lead to an optimistically 90% failure rate after people get their hands on them.

Proxies fall into this category. But we do have a problem that needs to be solved. You see, these guys at this standards body, they wrote a bunch of standards for manipulating web pages and decided it would be a good idea to make that standard (you guessed it, the DOM) not actually be implementable in the language that comes in all the browsers. Instead it has to be implemented in C/C++ with “host object” bindings into JavaScript. Thanks W3C!

If the web had a motto it would be “suck it up.” We live with all the bugs and incompatibilities and build our products anyway. Proxies allow us to build in JavaScript what was previously only possible with host objects and there are at least 20 developers out there that really need to do this. We can warn all we want, people will still abuse this feature. Every talk on Python Meta Classes begins with “don’t use meta classes” but people won’t listen and continue to write code that confuses people way more than my old list comprehensions ever did.

It’s not all bad

WeakMap is something we would find useful in node. Because an author may want to keep a table of “inflight” objects for dynamic debugging you need a structure with different garbage collection semantics than regular objects or else it’s likely to leak.

And oh god, please, 64bit integers, please, please, please.

Now, why can’t these objects just be added to the global namespace in a version of ES that is compatible with ES5? Probably for the same reason we don’t backport features in new versions of node.js, to encourage adoption of the new version. I can’t knock this reasoning because I engage in it but it does mean that developers will be waiting much longer before they can use these, and we need them, like, yesterday.

Lexically scoped var, good! Oh wait, it’s not var though, it’s let and var is still around and scopes differently. sigh. Also, const is stupid. That’s a very plain way to describe it, but it’s true. It’s based on a false premise, that someone editing my code is likely to overwrite something they shouldn’t. Because you control the scope of your variables you control the mutability, so code outside your scope is no issue, and someone editing your code can just change it to var like I used to do whenever I encountered them during my time at Mozilla. But we’re suppose to be talking about positive things :)

Destructuring reduces boiler plate, which is great. It’s also in a rare class of new features whose syntax feels like it really belongs. The semantics are obvious the first time you see it, more things like this please.

Winning

Something upset me about Alex’s article on classes. It wasn’t him calling me out, strangely for a feature I’m less opposed to than most, but his overall tone. In the world that Alex paints it looks like JavaScript is failing.

Don’t add classes and the world at large thinks of JS as a joke and a toy

Last time I checked, JavaScript is the most widely implemented and fastest growing language in the world. On the node.js side, we’ve got everyone from old school systems programmers to Rails coders jumping on board. JavaScript is on every computer, every mobile device, and we even beat Ruby on GitHub. We still have room to grow, but our trend line appears to be going up.

JavaScript did something right and it’s strange to me that we would want to change the language in a way that will appeal to a shrinking population of people we have yet to reach.

Because of the language’s history and varied implementation it lacks a strong identity. Rails and Python are not for everyone and when a feature doesn’t appeal to a particular group they don’t see that as a failure of the language but more of a cultural difference.

It is my belief that the lack of semantics and features in JavaScript has attributed strongly to its success. Of course, I have no proof. But Alex has no proof that adding classes will attract Java programmers. Nobody knows exactly why the language has done so well or definitively what would attract more. All we can do is try to make it better for the people already using it.

Node.js has shown us that this language has legs even if when it’s not bundled in all the browsers. JavaScript is not the defacto standard of the backend world. The growth of node is so dramatic it cannot be explained with “it’s the same language as the browser.” We actually have some proof here that, even when not coerced, JavaScript is appealing to programmers.

We don’t know what makes this language so sticky but when I ask people like Ryan Dahl and Isaac Schlueter, they tend to say, “Because it’s not changing.”