title: JavaScript 2 and the Open Web
Brendan Eich (Mozilla) @media Ajax London, November 2007
(Adapted S9 Version from Original S5 Slide Deck)
- Browser, plugin, and OS vendors?
- Web developers?
- All of the above, ideally
- Without taking too long
- Or making a mess
- Preventing change could spare us from "worse"
- Or help proprietary "change" to take off for the worst
- Web browsers are evolving
- They need to, against Microsoft Silverlight, Adobe Intergrated Runtime (AIR), and OS stacks
- Browsers (and plugins!) need all three of
- Better Security
- Better APIs for everything (see 1)
- Better programming language support (see 1 and 2)
- No two-legged stools, all three are needed
- Security: hard problem, humans too much in the loop
- Good ideas (Caja: Capability Javascript) being tried now
- Soundness still elusive
- APIs: served by Web Hypertext Application Technology Working Group (WHAT-WG) (Apple, Mozilla, Opera)
- and Google Gears
- and perhaps ScreamingMonkey ?
- Internet Explorer 8 (IE8)... who knows?
- Languages: only realistic hope in the short run is JavaScript 2
- Why not new/other programming languages?
- JavaScript not going away in our lifetimes
- JavaScript code is growing, not being rewritten
- No room for multiple language runtimes in mobile browser
- Apple, Mozilla, Opera attest to this in my hearing
- One multi-language runtime? Eventually, not soon enough
- A patent minefield...
- How many hard problems can we (everyone!) solve at once and quickly?
- JavaScript 1 is too small => complexity tax on library and app authors
- JavaScript 1 has too few primitives => hard idiom optimization problem
- JavaScript 1 lacks integrity features => better security has to be bolted on
- JavaScript 1 is not taught much => Java U. still cranking out programmers
- JavaScript 2 aims to cover the whole user curve, "out of the box"
Perhaps you object (strenously):
- I like my JavaScript small, it is not complex with the right kung-fu!
- Most runtime is in the DOM, who cares about JavaScript optimizations
- Security through smallness, and anyway: fix security first
- People are learning, Yoda is teaching them
- Some truth in these claims, just not enough in my view
- The odds ratios multiply to a pretty small success likelihood
- Meanwhile, Microsoft Silverlight is charging hard with C# (DLR fan-bait aside)
- Adobe Flash and Adobe Integrated Runtime (AIR) likewise rely on ActionScript 3, not JavaScript 1, to compete
- And really, JavaScript 1 users who are hitting its limits need relief soon
- We're not proto-humans from 2001: A Space Odyssey
- Making space ships out of bones
- Or modules out of lambdas
- We're highly-evolved tool users, with opposable thumbs -- we can:
- Make better use of an existing tool (JavaScript 1)
- Improve the tool itself (JavaScript 2)
- Why not do both?
You may still object:
- JavaScript should remain small no matter what!
- Classes suck, I hate my pointy-haired Java boss
- Aren't you rejecting your own elegant (yet messy) creation?
- Who replaced you with a pod-person? We don't even know you any longer!
- To make JavaScript (not people)... better
- Better for its present and near-future uses on the web
- Especially for building Ajax libraries and applications
- JavaScript programs are increasing in size and complexity
- They face increasing workload -- lots of objects, runtime
- JavaScript users deserve improvements since JavaScript 1/EmcaScript 3 (eight years ago)
- JavaScript users deserve an optional type system
- Instead of tedious (often skipped) error checking
- So APIs can prove facts about their arguments
- Without requiring all calling code to be typed
- (... at first, or ever!)
- They deserve integrity guarantees such as
const - They deserve real namespaces, packages, compilation units
- They deserve some overdue "bug fixes" to the EmcaScript 3 (ES3) standard
- They deserve generous syntactic sugar on top
Why JavaScript 2 as a major evolutionary jump matters:
- So browsers and plugins lose their "native-code innovation" lock
- Downloaded JavaScript 2 code can patch around old native code bugs
- Or reimplement a whole buggy subsystem, at near-native (or better!) speed
- No more waiting for Internet Explorer(or Firefox, or Safari, or Opera)
- Distributed extensibility, web developers win
- Yes, this was the Java dream that died in 1995, or 1997
- This time for sure (Tamarin may be the most widely deployed VM ever)
- It's coming true with JavaScript -- if only it can evolve enough in time
- JavaScript 1 performance on synthetic pure-JavaScript (no DOM) benchmarks
- Trace-based JITing accelerates JavaScript 1 at least an order of magnitude
- Work from Michael Franz's group at UC Irvine (Mozilla supported)
- No
inttype annotations required - Preliminary results (from submitted papers) based on Tamarin-to-Java bytecode translation, with a custom tracing JIT targeting the JVM (whew!), next...
- Making JavaScript 2 look like any other language
- Stuart, yesterday : fans already fake JavaScript 1 to resemble Ruby, Python, ...
- But: JavaScript 2 learns from other languages
- ActionScript 3: nominal types, namespaces, packages
- Python: iterators and generators, catch-alls
- Dylan, Cecil: generic methods
- Only those who don't learn history are doomed to repeat it
- Problems will be shaken out in JavaScript 2/EmcaScript 4 "beta"
- No rubber-stamped standards! (cough OOXML)
- Object, Array, etc., globals can be replaced in JavaScript 1
- JSON CSRF hazards pointed out by Joe Walker
- ECMA spec says this matters, or not, half the time
- JavaScript 2 makes the standard class bindings immutable
- Objects are mutable, extensible
- Even with privileged/private members via closures
- Too easy to forge instance of special type
- JavaScript 2 has
classexactly to solve this problem - JavaScript 2 lets users make fixtures, fixed ("don't delete") properties
- JavaScript 1 user-defined properties can be replaced/hijacked
- JavaScript 2 has
constandfinal
- JavaScript 2 has
Version 1 of a webmail client, in almost pure JavaScript 1
function send(msg) {
validateMessage(msg);
msg.id = sendToServer(JSON.encode(msg));
database[msg.id] = msg;
}
function fetch() {
handleMessage(-1); // -1 means "get new mail"
}
function get(n) {
if (uint(n) !== n) // JS1: n>>>0 === n
throw new TypeError;
if (n in database)
return database[n];
return handleMessage(n);
}
var database = [];
function handleMessage(n) {
let msg = JSON.decode(fetchFromServer(n));
if (typeof msg != "object")
throw new TypeError;
if (msg.result == "no data")
return null;
validateMessage(msg);
return database[msg.id] = msg;
}
function validateMessage(msg) {
function isAddress(a)
typeof a == "object" && a != null &&
typeof a.at == "object" && msg != null &&
typeof a.at[0] == "string" && typeof a.at[1] == "string" &&
typeof a.name == "string";
if (!(typeof msg == "object" && msg != null &&
typeof msg.id == "number" && uint(msg.id) === msg.id &&
typeof msg.to == "object" && msg != null &&
msg.to instanceof Array && msg.to.every(isAddress) &&
isAddress(msg.from) && typeof msg.subject == "string" &&
typeof msg.body == "string"))
throw new TypeError;
}
Version 2: Structural types for validation.
type Addr = { at: [string, string], name: string };
type Msg = {
to: [Addr], from: Addr, subject: string, body: string, id: uint
};
function send(msg: like Msg) {
msg.id = sendToServer(JSON.encode(msg));
database[msg.id] = msg;
}
function fetch()
handleMessage(-1);
function get(n: uint) {
if (n in database)
return database[n];
return handleMessage(n);
}
function handleMessage(n) {
let msg = JSON.decode(fetchFromServer(n));
if (msg is like { result: string } && msg.result == "no data")
return null;
if (msg is like Msg)
return database[msg.id] = msg;
throw new TypeError;
}
Version 3a: Integrity through structural type fixtures (other functions are unchanged since Version 2)
type MsgNoId = {
to: [Addr], from: Addr, subject: string, body: string
};
function send(msg: like MsgNoId) {
msg.id = sendToServer(JSON.encode(msg));
database[msg.id] = copyMessage(msg);
}
function handleMessage(n) {
let msg = JSON.decode(fetchFromServer(n));
if (msg is like { result: string } && msg.result == "no data")
return null;
if (msg is like Msg)
return database[id] = copyMessage(msg);
throw new TypeError;
}
function copyMessage(msg) {
function newAddr({ at: [user, host], name })
new Addr([user, host]: [string, string], name);
let { to, from, subject, body, id } = msg;
return new Msg(to.map(newAddr), newAddr(from),
subject, body, id);
}
Version 3b (other functions are unchanged since Version 3a)
function send(msg: like MsgNoId) {
msg.id = sendToServer(JSON.encode(msg))
database[msg.id] = msg wrap Msg
}
function handleMessage(n) {
let msg = JSON.decode(fetchFromServer(n))
if (msg is like { result: string } && msg.result == "no data")
return null
return database[msg.id] = msg wrap Msg
}
- At no point so far did clients have to use types
- Code shrank by half from stage 1 to 3a, more to 3b
- First stage just used a tiny bit of JavaScript 2 (
uint) - Second stage added structural types and
is liketests- Sanity-checking the "shape" of API arguments
- But trusting the client not to mutate behind the library's back!
- Third stage copied into structural type instances with fixtures -- integrity against confused/malicious client
- Alternative third stage used
wrapinstead
- A "modularization" stage would use
packageornamespace - If copying or wrapping too costly, drop
likefrom formal params, and either:- Change client to pass structural type instances
- Or use nominal types (
class,interface) throughout - Either way, client changes required at this point
- Use optional strict mode for verification before deployment
- (Many thanks to Lars Thomas Hansen for the example code)
- JavaScript 2 focused on programming in the large and code migration:
- Evolutionary programming with structural types
- Gradual typing from
liketowrapor fixed types
- Rapid prototypes start out untyped, just like today
- We believe most web JavaScript can remain untyped, with good performance
- Library APIs and implementations can buy integrity and efficiency by the yard
- Higher integrity with efficiency may induce more "islands" of typed code (e.g., real-time games)
- ScreamingMonkey lives! It runs a self-hosted JavaScript 2/EmcaScript 4 compiler that generates bytecode from the compiler's own source
- Much optimization work remains to be done
- But the C# chess demo from MIX07, ported to EmcaScript 4, runs now
- ScreamingMonkey chess demo is ~15x faster than the JScript version (per fresh e-mail today from Mark Hammond)
- Demos of two other new APIs, the
<video>tag and 3D<canvas>, follow...
- Implements the WHAT-WG
<video>tag proposal - Opera and now Apple have implemented too
- page-defined DHTML playback controls
- Uses Ogg Theora and Vorbis for video and audio
- Embeds
<video>in SVG<foreignObject>for transforms - Developed by Chris Double
- Alternative OpenGL-ES rendering context for
<canvas> - Now available as a Firefox 3 addon!
- Embeds OpenGL's shader language in
<script>, read via DOM - Example KMZ (Google Earth) viewer
- Developed by Vladimir Vukicevic


