title: JavaScript 2 and the Open Web h1. JavaScript 2 and the Open Web Brendan Eich (Mozilla) @media Ajax London, November 2007 (Adapted S9 Version From Original S5 Slide Deck) h1. Cui Bono - Who decides what is "better"? * 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 h1. Inevitable Evolution * 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 h1. Evolving Toward "Better" * Security: hard problem, humans too much in the loop ** Good ideas ("Caja: Capability Javascript":http://www.google.com/search?q=google+caja+paper) being tried now ** Soundness still elusive * APIs: served by Web Hypertext Application Technology Working Group "(WHAT-WG)":http://www.whatwg.org (Apple, Mozilla, Opera) ** and "Google Gears":http://code.google.com/apis/gears/ ** and perhaps "ScreamingMonkey":http://wiki.mozilla.org/Tamarin:ScreamingMonkey ? ** Internet Explorer 8 (IE8)... who knows? * Languages: only realistic hope in the short run is JavaScript 2 h1. Alternative Languages * 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? h1. Why JavaScript 2 * 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" h1. Normal Distribution !BellCurve.png! h1. Wait a Minute! 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 h1. OK, Granted * 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 h1. Why Not Evolve? * 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? h1. But... But... 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! h1. What I Seek * 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) h1. In Particular * 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 h1. The Deeper Answer 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 h1. Believe It * 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 h1. Non-Issues * 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 @int@ type annotations required * Preliminary results (from submitted papers) based on Tamarin-to-Java bytecode translation, with a custom tracing JIT targeting the JVM (whew!), next... h1. Tracing JIT Benchmarks !JavaGrandeA.png! h1. Tracing JIT Benchmarks !JavaGrandeB.png! h1. Non-Issues (2) * Making JavaScript 2 look like any other language * "Stuart, yesterday":http://www.vivabit.com/atmediaAjax/sessions/#how : 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) h1. Integrity in JavaScript 2 * Object, Array, etc., globals can be replaced in JavaScript 1 ** JSON CSRF hazards pointed out by "Joe Walker":http://getahead.org/blog/joe/2007/03/05/json_is_not_as_safe_as_people_think_it_is.html ** 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 @class@ exactly 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 @const@ and @final@ h1. Evolutionary Programming 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" } }}} h1. Evolutionary Programming (2) {{{ 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 = []; }}} h1. Evolutionary Programming (3) {{{ 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; } }}} h1. Evolutionary Programming (4) {{{ 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; } }}} h1. Evolution, Second Stage 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); }}} h1. Evolution, Second Stage {{{ 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; } }}} h1. Evolution, Third Stage 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); } }}} h1. Evolution, Third Stage (2) {{{ 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; } }}} h1. Evolution, Third Stage (3) {{{ 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); } }}} h1. Alternative Third Stage 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 } }}} h1. Observations on Evolution * 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 like@ tests ** 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 @wrap@ instead h1. Observations on Evolution (2) * A "modularization" stage would use @package@ or @namespace@ * If copying or wrapping too costly, drop @like@ from 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) h1. Conclusions * JavaScript 2 focused on programming in the large and code migration: ** Evolutionary programming with structural types ** Gradual typing from @like@ to @wrap@ or 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) h1. What Else Is New? * "ScreamingMonkey":http://wiki.mozilla.org/Tamarin: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":http://on10.net/Blogs/tina/microsoft-silverlight-chess/ 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 @