
The Future of JavaScript - JoshTriplett
http://blog.chromium.org/2012/02/future-of-javascript-take-peek-today.html
======
geuis
I'm probably alone in saying this, but I hope most of this stuff never sees
the light of day.

What makes JS powerful is its simplicity. "var" or no "var" gets you local or
global scope. Done. Want a constant? Make a global variable and don't change
it. Want to really make sure its unchangeable? Make an accessor function.

Scope in JS is very simple to understand and quite versatile once understood.
Adding more layers of complexity does _not_ help.

One of the strengths of js is that _every thing is an object_ (almost). So the
bit about "no more need to abuse objects as dictionaries" is a bit odd. Since
most things are objects, you get the power to treat functions, types,
literals, etc in interesting ways.

One of the strengths of object literals is that you _can_ use them as
dictionaries. obj.foo === obj['foo'].

I love getters/setters and some other improvements like strict mode. However I
am very much against what seems like an unnecessary cluttering of the language
without fixing some of the long standing problems like ==/===. For me, I
almost never use == so it should be gotten rid of. Make == === === for
example.

~~~
ireadzalot
In my experience, the charm of simplicity of JS starts fading away when you
start moving away from DOM manipulation and start writing complex objects.
Just last week I ran into the lexical scoping issue ( I was not aware of it
before) that had me scratching my head for hours. Scoping in JS becomes less
fun the deeper you start digging. I am glad that they are aware of it and are
actively trying to address it.

~~~
thaumaturgy
I agree with geuis, and I've written a personal-use JS framework that's in the
same ballpark as jquery. I've run into the lexical scoping issue, but not for
a long time. Straightforward naming conventions and Firebug can track down
scoping problems really quickly.

I'm not really opposed to the changes to JS that are mentioned on the Chromium
blog, but mostly because I don't have to use them. I don't really see the
point of any of them -- and practically speaking, they won't see widespread
use anyway until IE 9 dies out -- but maybe I'm just not imaginative enough to
understand yet.

~~~
chc
I very rarely have problems with JavaScript scoping or any of those obvious
gotchas, but I still don't agree that they are _good_. We've just become
acclimated to the language's eccentricities, the same way people living in
Arizona for a long time think California summers are chilly.

It is true that JavaScript's scoping rules are pretty simple, but less is not
always more. Once you have learned all the patterns and gotchas, JavaScript's
scoping is quite usable. But the fact that you have to use patterns where you
wouldn't in another language means JavaScript is _making work for you_. If
JavaScript had Lispy macros or some other way of altering the language, I
might be more inclined to agree that the fundamental simplicity is a good
thing, but without that power, the simplicity means that when you're doing
complex things, the complexity missing from the language has to be written out
explicitly in your code. Right now a lot of JavaScript code is a mix of
function pasta and things that should be function pasta but the coder couldn't
be bothered.

~~~
telent
Yes. "let x=1" is quite clearly syntactic sugar for "(lambda(x) { ... rest of
block here ... })(1)" so while you might argue that it's unnecessary (I'd
disagree, but it's a respectable argument), you can't realistically claim that
it would be adding a layer of complexity. The complexity is there already: the
sugar is just encapsulating in a more eyeball-friendly format

------
jashkenas

        > No surprises, no more need to abuse objects as dictionaries.
    

... pretty much every single file of JS ever written is "guilty" of this.

~~~
Lewisham
I've only delved into really writing JS for the last couple of weeks, but a
number of tutorials basically said that objects _are_ dictionaries and vice
versa, you just got some nice syntax and you can plug function in as values.

If that was an abuse, what are JavaScript objects supposed to be? What's the
difference between them and a dictionary?

~~~
jashkenas
It's only an abuse because JavaScript has no distinction between the notion of
an object's "meta" properties, and its dictionary-like keys and values. So
you'll get along just fine, until someone tries to write this:

    
    
        var dict = {};
    
        dict["hasOwnProperty"] = true;
    
        dict["toString"] = "Bob";
    
        dict["valueOf"] = 7;
    

... then you're in for a rough time.

~~~
mbrubeck
Another problem with objects-as-dictionaries is that the keys must be strings.
If you use a different type as a key, it is implicitly converted to a string,
which can lead to some surprising problems for programmers who don't expect
it.

Maps/Set/WeakMap properly support arbitrary objects as keys.

~~~
grannyg00se
Again, this is something that is simple to learn and understand. And you would
learn this in a beginner tutorial. Why go through trouble to change it and
complicate the language even further? I undeerstand weakmap may have some real
advantage as far as GC, at least.

~~~
batista
_Again, this is something that is simple to learn and understand. And you
would learn this in a beginner tutorial. Why go through trouble to change it
and complicate the language even further?_

For one simple to understand != intuitive or easy to use. Chess rules are easy
to understand too, you can learn all of them in an hour, but try to play the
game with any quality. So this being simple to understand does not mean its
simple to code around and debug.

You are also misguided in that this addition "complicates the language". It's
not like adding generics or monads or some crazy new feature. It's one of the
most fundamental datatypes, implemented properly for the first time.

So, instead of saying Object foo; foo.x = "a"; when you need a dict, and
having to guard against all consequences, you get to use Map foo; foo.x = "a";
and there is nothing you have to think about anymore.

------
substack
I really dislike what they're doing with modules because it's such a step back
from the commonjs-inspired require() that node uses. In node, require() just
returns a value. That value is usually an object but often it's just a
function. Why should a module that encapsulates exactly one function return
anything else but that one function?

In ES.next, you've got to use pythonesque `import y from Bar` statements which
introduce a frustrating correspondence between the lexicals of your own
program and the export names of the module you're trying to use which is
really terrible if you're using as many modules as I typically do. I presume
ES.next will invent even more specific syntax for some sort of `as` like
keyword to side-step this but it seems so unnecessary when javascript already
has a module system that is so very good as is exploding in popularity and use
(>7000 modules now on <http://search.npmjs.org/>).

I understand what they're trying to do with static analysis too but you can
already pretty much do that and I've done it. It's not hard at all, just
ignore require() statements that don't contain strings when you walk the AST,
like this: <https://github.com/substack/node-detective>

Inventing more syntax instead of just adopting a far better module system that
has seen actual use in practical situations is such a shame and ES.next is
rife with this kind of prescriptivism. It irritates me to no end and I
sometimes want ES.next to die a quiet death in obscurity because of it.

<http://wiki.ecmascript.org/doku.php?id=harmony:modules>

~~~
samth
I'll try to separate out the different issues you're raising here, and respond
to each individually.

1\. What if I want to have my module be a function, the way that $ in jQuery
is both a function and a namespace for the rest of the functionality?

This is an important use case, and so we're going to support it in ES6
modules. You'll be able to say:

    
    
        module $ at "http://jquery.com/jquery.min.js";
        $(...)
        $.ajax(...)
    

2\. Modules will requiring using names without the prefix.

This isn't true. As you can see in the above example, you can just use $
directly, even though it's a module. You can also say:

    
    
       import ajax from $;
    

but you don't have to.

3\. We should just standardize the node module system.

Of course, there are many different module systems being used in JS code right
now, and we could just pick one. Unfortunately, we couldn't just pick the node
module system, since it's fundamentally synchronous, which is great on the
server side but not in the browser.

However, we feel that we can bring real advantages to JS programmers by
extending the language -- we can simplify using modules, we can make some
patterns direct that currently have to be written using callbacks, we can
better support encapsulation, and we can allow engines to use knowledge about
modules for optimization.

3\. Static analysis is doable even without a static module system.

The static analysis you describe, while useful, isn't going to tell an engine
statically where it can go to lookup references to an export from a module.
That means it's not useful for many of the optimizations that we want to
enable. Additionally, your analysis isn't sound -- it can miss uses of
`require` that are generated dynamically, for example. Again, that means that
engines can't use it for optimization.

Finally, if you have comments about ES development, I strongly encourage you
to make them on es-discuss, rather than on HN, where they are more likely to
have an impact on the development of the language.

~~~
samth
Since it came up on twitter, here's how you'd implement the `$` module I
describe above:

    
    
        export function ajax(...) { ... };
        
        // NB: not how jQuery actually works ;)
        export this(query) { return document.find(query); };
    

The `export this` syntax specifies how the module instance object behaves when
called as a function.

~~~
substack
Thanks for this. I'm glad that using a single export function will at least be
possible. I'm still pessimistic about the amount of syntax being introduced
here.

In particular, I still really dislike the special import "local renaming"
syntax since it seems so unnecessary compared to just having an import keyword
that returns an object and letting the programmer extract and manipulate the
relevant entries. You would still get the static analysis benefits of having
static imports without all the awkward complexity of the current proposal.
Wouldn't it just be the same thing to Object.freeze() the export object but
without any syntax magic necessary?

Plus, overloading `module` to do loading AND defining with the `module Bar at
"uri"` form seems really wrong. Why can't it JUST do defining and just let
import do all the loading?

~~~
samth
First, if you want to just use objects-as-prefixes, the way require(...) works
in node today, that's easy to do:

    
    
        module m at "blah.com";
        ... references to m go here ...
    

We also want to support other use cases, like binding the exports to names
available in your local scope. We understand that not everyone likes that
style, but I don't think the language should mandate a particular side in that
fight.

Second, the `module m at "URL"` form above _is_ a definition of `m`. It's just
that you're allowed to refer to that binding as an object too. Would you
rather have:

    
    
        module m at "example.com";
        import m;
    

That just seems like unnecessary typing to me.

~~~
substack
I mean why does `module` pull down resources? Shouldn't that be import's job?

~~~
samth
There are two reasons:

1\. `module` is about defining the modules that you're using in your program,
some of which might be remote resources. `import` is about bringing names into
scope.

2\. Using `module` this way lets you, the client, decide on names for modules,
which means we don't have to rely on module authors to come up with and use
naming conventions (net.substack.airport, anyone?).

This feeds back into 1, where we use bindings to reference modules, even
remote ones.

Also, if a module is never referenced or imported, then the resources
shouldn't need to be pulled down at all. So partly it depends on the way you
look at things.

------
herge

        > (Caveat: Iteration over collections is not yet specified)
    

Is this a joke? Is not iterating over dictionaries and arrays javascript's
most glaring weakness?

How hard would it be to agree on something like foreach, that, you know,
actually works the way you think it should work.

~~~
tikhonj
There is a foreach that works: .forEach(). And when you're not just iterating
over an array but transforming it, you have map(), reduce() and filter().

~~~
herge
Is it really too much to ask to have some syntactic sugar. Is

    
    
        for i,v in blah
    

, where i is an index of an array, or a key (not a property!) of a dictionary
really too much to ask in 2012?

No wonder people are using coffeescript.

~~~
jashkenas
CoffeeScript's got you covered. Here's forEach ...

    
    
        for item, index in list
    

... here's the same over an object ...

    
    
        for key, value of object
    

... here's the map() ...

    
    
        mapped = for item in list
    

... here's the filter() ...

    
    
        filtered = for item in list when item.isActive
    

... and so on.

~~~
herge
Exactly. The number one thing javascript should take from coffeescript is the
iteration syntax.

------
ootachi
Firefox nightlies have all of these features as well. Good to see Chrome
following suit.

~~~
karterk
Minor nitpick - FF has had let scoping for a long time. WeakMap has been
around since FF 6[1].

[1]:
[https://developer.mozilla.org/en/JavaScript/Reference/Global...](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/WeakMap)

------
grannyg00se
"Now "let" is the new "var" – traditional "var" declarations are complemented
with "let" and "const". Both are properly block-scoped bindings, eliminating a
common source of errors and weird behaviour."

Somehow going from one keyword for variable declaration to three doesn't seem
like a good way to reduce errors.

~~~
agscala
The extra keywords aren't going to reduce the "errors and weird behavior", the
fact that they will be block-scoped and not function-scoped is what will
eliminate the confusion.

~~~
ams6110
I agree with geuis above, JavaScript scope is simple to understand now. There
is global scope, and there is function scope. That's it. And there's a certain
elegance to that.

~~~
wingo
There are more scopes than that: free variables versus locals; eval-introduced
bindings; "with"; the exception identifier in "catch"; the function name in
named function expressions; argument names; etc.

And the scoping rules are quite tricky in practice, to real programmers. To
take an example from today:

<https://bugs.webkit.org/show_bug.cgi?id=27226#c4>

~~~
grannyg00se
Looking at that example, I would ask ....where exactly is that function
definition getting defined? Why would you put a function definition inside a
catch block? Do you think it's getting defined when the catch block is called?
Are you programming _in_ Javascript, or are you just writing javascript the
way you would write code in some other language?

~~~
sirclueless
It's a pretty straightforward use-case: you have a function that returns a
function, and in the case of an internal error, you want the returned function
to have a reference to the error object. And the only reliable way to do that
is to declare a variable with function scope, declare a function in function
scope, and conditionally return this function? That's absurdly broken.

As for variable scoping rules, if you have never been bitten by loop counters
being used improperly, then I assert that you haven't programmed enough
javascript. There are so many ways to mess this up: forget a var declaration
and it leaks scope -- and since you can only declare it once, you can't just
always use "for (var i = ...". If you want to defer access to a loop counter,
then you have to remember to explicitly pass it by value to an inner closure.
That last one in particular bites me all the time -- JSLint at least warns you
about the first one.

------
Siverv
Would there be any possibility for the addition of native Long numbers to
JavaScript, or is this, due to some nature of the language, something that
can't, or shouldn't, be included?

~~~
JoshTriplett
I'd settle for integers. :)

------
ypcx
Anyone know where can I request a OrderedMap? That committee Wiki seems
hardened against intruders.

Would be really unfortunate to have to wait for a native
OrderedMap/SortedMap/TreeMap until ES7.

~~~
heydenberk
Bring it up on es-discuss <https://mail.mozilla.org/listinfo/es-discuss>

But _please_ , search the archives first and be aware of what discussions have
already taken place on this subject. =]

------
msie
_It is due by the end of next year_

Ouch. I guess the end of 2013 is sooner than never.

------
haberman
> The ECMA committee is working hard on designing

"Committee" and "designing" in the same sentence gives me the shivers.

But the features they're describing actually sound pretty reasonable. Actually
a lot of them seem to already exist in Lua ("proxies" sound like what are
provided by Lua's metatables, and Lua already has weak tables and lexical
scoping).

------
boyo
Lexical scoping, strict mode, hash tables. Is it just me, or did this post
make JS sound a little ... Perlish?

------
akavlie
I had been wondering when Harmony was due. The end of NEXT year? Wow, that's a
long wait.

------
winteriscomming
Is it really not out for 2 years? Really? That seems like a long time for not
that much changes. Any improvement is welcome, but still. I don't know if this
will keep pace with Dart and other options. It seems way too slow.

~~~
fourstar
Really?

You seriously think Dart is anywhere close to taking over Javascript?

~~~
winteriscomming
No I don't but my point is that 2 years seems a bit slow as far as evolution
of JS is concerned.

------
heydenberk
The post links to an outdated Proxy spec. Here's the right link:
[http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxie...](http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies)

~~~
heydenberk
Also, this is a great paper posted on ES-discuss about Proxies:
[https://mail.mozilla.org/pipermail/es-
discuss/attachments/20...](https://mail.mozilla.org/pipermail/es-
discuss/attachments/20120208/e3f5075b/attachment-0001.pdf)

------
wslh
Futures like in node-fibers? <https://github.com/laverdet/node-fibers> I think
it is the proper way to complement generators and give the alternative to wait
for a function value.

~~~
zoips
I don't think there's a reason to bake futures/promises into the language.
Once you've got coroutines (generators here), people can build the
abstractions around them that they like.

------
marknadal
Could somebody clarify, but I feel like I won't ever use this. Older browsers
won't understand these new "features", so I still will have to code as I am
used to. So I guess in 20 years... I might dabble with them.

~~~
JoshTriplett
You can use this any time you know your target environment. For instance, if
you write JavaScript for Firefox addons, Greasemonkey scripts, Chrome
extensions, or node.js, you know exactly what JavaScript engine you'll run on,
and you can take advantage of new JavaScript features that engine implements.

You can also use new JavaScript features the same way you use other new
browser features like WebSocket or cross-domain xmlHttpRequest: when you've
determined that all the modern browsers implement the feature you care about.
The browser vendors reach a point where they stop supporting older versions
with security updates and similar; I'd consider it reasonable to stop
supporting a browser when it stops receiving security updates. (You should
also evaluate your audience and the browsers they actually use.) At that
point, older browsers get the same experience as links or wget: they get the
content, but not the enhancements provided by JavaScript or whatever other
features you use.

------
firefoxman1
After reading many of really great comments on this post, I think that
additions to a language deserve community input. Not just a couple of the
"Best" programmers sitting around a table deciding.

This is the Web, after all. An interconnected world-wide community. Why isn't
there some sort of voting process that anyone can give their input for
ECMAScript's drafts? Right now it's an Oligarchy. At the very least, an
electoral college-like system would be nice.

------
aledalgrande
As long as this doesn't become another difference between browsers (=
headache).

~~~
nas
Even with optimistic estimates, it's going to be years, likely decades, before
you can rely on these features being supported by the majorly of browsers.
That's kind of sad but is the hard reality. I hope they come up with a good
design.

I think they should be very conservative about what they propose. It should be
a very obvious improvement to the language or have a lot of design time spent
on it. If all major browser developers are not on board (Microsoft?) then the
improvement is much less valuable.

------
batista
It would be nice if there was some mechanism --at least for dynamic
languages-- where when a feature X (say, the new "let" keyword) is introduced
in the compiler, you can add some code that adds support for it at runtime.
Maybe with some kind of name-mangling to avoid name clashes with existing
variable names, etc.

Of course it would incur a performance penalty, and for some stuff it might
also be infeasible, but there could be some low level package just for this
purpose, that provided options to add new keywords, bytecodes, etc.

The end result would be something like (in mock-pyjs glory):

if __language__.has_not("let") import __Future__.Let".

This would enable faster iterations of the main language, while keeping
backwards compatibility. Anyone knows if anything like this exists?

(Well, you can do sort of this kind of thing in Lisp. But has it ever been
attempted in a C-like syntax?)

P.S My understanding is that Python does not do this, it just makes the
__future__ imported modules optional in the previous version of the compiler,
but they are still implemented in plain C along with the rest of CPython, no?

~~~
JoshTriplett
Personally, I'd love to see an implementation of ES.next as a static compiler.
Much like CoffeeScript provides a JavaScript-like language that compiles to
JavaScript, an ES.next compiler could compile ES.next JavaScript to cross-
browser JavaScript.

