Evolving js


Published on


Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Evolving js

  1. 1. JavaScript 2.0: Evolving a Language for Evolving Systems Waldemar Horwat waldemar@acm.orgAbstractJavaScript 2.0 is the next major revision of the JavaScript language. Also known as ECMAScriptEdition 4, it is being standardized by the ECMA organization. This paper summarizes the needsthat drove the revision in the language and then describes some of the major new features of thelanguage to meet those needs — support for API evolution, classes, packages, object protection,dynamic types, and scoping. JavaScript is a very widely used language, and evolving it presentedmany unique challenges as well as some opportunities. The emphasis is on the rationale, insights,and constraints that led to the features rather than trying to describe the complete language. Netscape browsers through an interface1 Introduction called LiveConnect. JavaScript as a language has computational1.1 Background facilities only — there are no input/outputJavaScript [6][8] is a web scripting language primitives defined within the language. In-invented by Brendan Eich at Netscape. This stead, each embedding of JavaScript withinlanguage first appeared in 1996 as a particular environment provides the meansJavaScript 1.0 in Navigator 2.0. Since then to interact with that environment. Within athe language has undergone numerous addi- web browser JavaScript is used in conjunc-tions and revisions [6], and the most recent tion with a set of common interfaces, in-released version is JavaScript 1.5. cluding the Document Object Model [11], which allow JavaScript programs to interactJavaScript has been enormously successful with web pages and the user. These inter-— it is more than an order of magnitude faces are described by separate standardsmore widely used than all other web client and are not part of the JavaScript languagelanguages combined. More than 25% of web itself. This paper concentrates on thepages use JavaScript. JavaScript language rather than the inter- faces.JavaScript programs are distributed insource form, often embedded inside webpage elements, thus making it easy to author 1.2 Standardizationthem without any tools other than a text After Netscape released JavaScript in Navi-editor. This also makes it easier to learn the gator 2.0, Microsoft implemented the lan-language by examining existing web pages. guage, calling it JScript, in Internet Ex- plorer 3.0. Netscape, Microsoft, and a num-There is a plethora of synonymous names ber of other companies got together andfor JavaScript. JavaScript, JScript, and formed the TC39 committee in the ECMAECMAScript are all the same language.JavaScript was originally called LiveScript standards organization [2] in order to agree on a common definition of the language.but was renamed to JavaScript just before it The first ECMA standard [3], calling thewas released. JavaScript is not related toJava, although the two language implemen- language ECMAScript, was adopted by the ECMA general assembly in June 1997 as thetations can communicate with each other in ECMA-262 standard. The second edition ofJavaScript 2.0: Evolving a Language for Evolving Systems 1
  2. 2. this standard, ECMA-262 Edition 2 [4], con- attributes and conditional compilation (Sec-sisted mainly of editorial fixes gathered in tion 8). Section 9 concludes.the process of making the ECMAScript ISOstandard 16262. The third edition of theECMAScript standard [5] was adopted in 2 JavaScript 1.5December 1999 and added numerous new JavaScript 1.5 (ECMAScript Edition 3) is anfeatures, including regular expressions, object-based scripting language with a syn-nested functions and closures, array and ob- tax similar to C and Java. Statements such asject literals, the switch and do-while i f , w h i l e , f o r , s w i t c h , andstatements, and exceptions. JavaScript 1.5 throw/try/c a t c h will be familiar tofully implements ECMAScript Edition 3. C/C++ or Java programmers. Functions,I’ve been involved at Netscape with both the declared using the function keyword, canimplementation and standardization of nest and form true closures. For example,JavaScript since 1998. I wrote parts of the given the definitionsECMAScript Edition 3 standard and am cur- function square(x) {rently the editor of the draft ECMAScript return x*x;Edition 4 standard. }In Editions 1 and 2, the ECMA committee function add(a) {standardized existing practice, as the lan- return function(b) {guage had already been implemented by return a+b;Netscape, and Microsoft closely mirrored }that implementation. In Edition 3, the role of }the committee shifted to become more active evaluating the expressions below producesin the definition of new language features the values listed after the fi symbols:before they were implemented by the ven- square(5) fi 25dors; without this approach, the vendors’ var f = add(3);implementations would have quickly di- var g = add(6);verged. This role continues with Edition 4, f(1) fi 4;and, as a result, the interesting language de- g(5) fi 11;sign discussions take place mainly withinthe ECMA TC39 (now TC39TG1) working A function without a return statementgroup. returns the value undefined.This paper presents the results of a few of Like Lisp, JavaScript provides an e v a lthese discussions. Although many of the is- function that takes a string and compiles andsues have been settled, Edition 4 has not yet evaluates it as a JavaScript program; thisbeen approved or even specified in every allows self-constructing and self-modifyingdetail. It is still likely to change and should code. For example:definitely be considered a preliminary draft. eval("square(8)+3") fi 67 eval("square = f") fi The1.3 Outline source code for function fSection 2 gives a brief description of the square(2) fi 5existing language JavaScript 1.5. Section 3summarizes the motivation behind Java- 2.1 Values and VariablesScript 2.0. Individual areas and decisions arecovered in subsequent sections: types (Sec- The basic values of JavaScript 1.5 are num-tion 4); scoping and syntax issues (Sec- bers (double-precision IEEE floating-pointtion 5); classes (Section 6); namespaces, values including +0.0, –0.0, +∞, –∞, andversioning, and packages (Section 7); and NaN), booleans (t r u e and false), theJavaScript 2.0: Evolving a Language for Evolving Systems 2
  3. 3. special values null and undefined, im- strange("Apple ", false) fimutable Unicode strings, and general ob- "Apple Hello"jects, which include arrays, regular expres- strange(20, true) fisions, dates, functions, and user-defined ob- "40Hello"jects. All values have unlimited lifetime and The last example also shows that + is poly-are deleted only via garbage collection, morphic — it adds numbers, concatenateswhich is transparent to the programmer. strings, and, when given a string and a num- ber, converts the number to a string andVariables are not statically typed and can concatenates it with the other string.hold any value. Variables are introducedusing var declarations as in: var x; 2.2 Objects var y = z+5; JavaScript 1.5 does not have classes; in- stead, general objects use a prototypeAn uninitialized variable gets the value mechanism to mimic inheritance. Every ob-undefined. Variable declarations are ject is a collection of name-value pairslexically scoped, but only at function called properties, as well as a few special,boundaries — all declarations directly hidden properties. One of the hidden prop-within a function apply to the entire func- erties is a prototype link1 which points totion, even above the point of declaration. another object or null.Local blocks do not form scopes. If a func-tion accesses an undeclared variable, it is When reading property p of object x usingassumed to be a global variable. For exam- the expression x.p, the object x is searchedple, in the definitions first for a property named p. If there is one, function init(a) { its value is returned; if not, x’s prototype b = a; (let’s call it y) is searched for a property } named p. If there isn’t one, y’s prototype is searched next and so on. If no property at all function strange(s, t) { is found, the result is the value a = s; undefined. if (t) { var a; When writing property p of object x using a = a+a; the expression x.p = v, a property named p } is created in x if it’s not there already and return a+b; then assigned the value v. x’s prototype is } not affected by the assignment. The newfunction strange defines a local variable property p in x will then shadow any prop-a. It doesn’t matter that the var statement is erty with the same name in x’s prototype andnested within the if statement — the var can only be removed using the expressionstatement creates a at the beginning of the delete x.p.function regardless of the value of t. A property can be read or written using anAt this point evaluating indirect name with the syntax x[s], where s strange("Apple ", false) is an expression that evaluates to a string (orsignals an error because the global variable a value that can be converted into a string)b is not defined. However, the following representing a property name. If s containsstatements evaluate successfully because the string "blue", then the expressioninit creates the global variable b: x[s] is equivalent to x.blue. An array is init("Hello") fi undefined 1 For historical reasons in Netscape’s JavaScript this hidden prototype link is accessible as the property named __proto__, but this is not part of the ECMA standard.JavaScript 2.0: Evolving a Language for Evolving Systems 3
  4. 4. an object with properties named "0", "1", method can refer to the object on which it"2", …, "576", etc.; not all of these need was invoked using the this variable:be present, so arrays are naturally sparse. function Radius() {An object is created by using the new op- return Math.sqrt(erator on any function call: new f(args). this.x*this.x +An object with no properties is created be- this.y*this.y);fore entering the function and is accessible }from inside the function via the this vari- The following statement attaches Radiusable. as a property named radius visible fromThe function f itself is an object with several any Point object via its prototype:properties. In particular, f.prototype Point.prototype.radius =points to the prototype that will be used for Radius;objects created via new f(args).2 An ex-ample illustrates these concepts: a.radius() fi 5 function Point(px, py) { this.x = px; The situation becomes much more compli- this.y = py; cated when trying to define a prototype- } based hierarchy more than one level deep. There are many subtle issues [9], and it is a = new Point(3,4); easy to define one with either too much or origin = new Point(0,0); too little sharing. a.x fi 3 a["y"] fi 4 2.3 Permissiveness JavaScript 1.5 is very permissive — strings,The prototype can be altered dynamically: numbers, and other values are freely coerced Point.prototype.color = into one another; functions can be called "red"; with the wrong number of arguments; global a.color fi "red" variable declarations can be omitted; and origin.color fi "red" semicolons separating statements on differ- ent lines may be omitted in unambiguousThe object a can shadow its prototype as situations. This permissiveness is a mixedwell as acquire extra properties: blessing — in some situations it makes it a.color = "blue"; easier to write programs, but in others it a.weight = "heavy"; makes it easier to suffer from hidden and confusing errors. a.color fi "blue" a.weight fi "heavy" For example, nothing in JavaScript distin- origin.color fi "red" guishes among regular functions (square origin.weight fi undefined in the examples above), functions intended as constructors (Point), and functions in-Methods can be attached to objects or their tended as methods (Radius). JavaScriptprototypes. A method is any function. The lets one call P o i n t defined above as a function (without new and without attaching it to an object),2 Using the notation from the previous footnote, after p = Point(3)o = new f(args), o.__proto__ == f.prototype. which creates global variables x and y iff.prototype is not to be confused with function f’s ownprototype f.__proto__, which points to the global proto- they didn’t already exist (or overwrites themtype of functions Function.prototype. if they did) and then writes 3 to x andJavaScript 2.0: Evolving a Language for Evolving Systems 4
  5. 5. undefined to y. The variable p gets the 3.2 Mechanismsvalue undefined. Obvious, right? (If thisis obvious, then you’ve been spending far A package facility (separable libraries thattoo much time reading language standards.)3 export top-level definitions — see section 7) helps with some of the above requirements but, by itself, is not sufficient. Unlike exist-2.4 Exploring Further ing JavaScript programs which tend to beThis is only a brief overview of JavaScript monolithic, packages and their clients are1.5. See a good reference [6] for the details. typically written by different people at dif-To get an interactive JavaScript shell, type ferent times. This presents the problem ofjavascript: as the URL in a Netscape the author or maintainer of a package notbrowser or download and compile the source having access to all of its clients to test thecode for a simple stand-alone JavaScript package, or, conversely, the author of a cli-shell from [8]. ent not having access to all versions of the package to test against — even if the author of a client could test his client against all ex-3 JavaScript 2.0 Motivation isting versions of a package, he is not able to test against future versions. Merely addingJavaScript 2.0 is Netscape’s implementation packages to a language without solvingof the ECMAScript Edition 4 standard cur- these problems would not achieve robust-rently under development. The proposed ness; instead, additional facilities for defin-standard is motivated by the need to achieve ing stronger boundaries between packagesbetter support for programming in the large and clients are needed.as well as fix some of the existing problemsin JavaScript (section 5). One approach that helps is to make the lan- guage more disciplined by adding optional types and type-checking (section 4). Another3.1 Programming in the Large is a coherent and disciplined syntax for de-As used here, programming in the large does fining classes (section 6) together with a ro-not mean writing large programs. Rather, it bust means for versioning of classes. Unlikerefers to: JavaScript 1.5, the author of a class can • Programs written by more than one per- guarantee invariants concerning its instances son and can control access to its instances, • Programs assembled from components making the package author’s job tractable. (packages) Versioning (section 7) and enforceable in- variants simplify the package author’s job of • Programs that live in heterogeneous en- evolving an already-published package, per- vironments haps expanding its exposed interface, with- • Programs that use or expose evolving out breaking existing clients. Conditional interfaces compilation (section 8) allows the author of • Long-lived programs that evolve over a client to craft a program that works in a time variety of environments, taking advantage ofMany applications on the web fall into one optional packages if they are provided andor more of these categories. using workarounds if not. To work in multi-language environments, JavaScript 2.0 provides better mappings for data types and interfaces commonly exposed by other languages. It includes support for3 The reason that global variables x and y got created is that classes as well as previously missing basicwhen one doesn’t specify a this value when calling a func-tion such as Point, then this refers to the global scope types such as long.object; thus this.x = px creates the global variable x.JavaScript 2.0: Evolving a Language for Evolving Systems 5
  6. 6. 3.3 Non-Goals var v:type = value; where v is the name of the variable and typeJavaScript 2.0 is intended for a specific is a constant expression that evaluates to aniche of scripting languages. It is meant to type. Types can also be attached to functionbe a glue language. It is not meant to be: parameters and results. • a high-performance language • a language for writing general-purpose A variable declared with a type is guaran- applications such as spreadsheets, word teed to always hold an element of that type5. processors, etc. Assigning a value to that variable coerces • a language for writing huge programs the value to the type or generates an error if the coercion is not allowed. To catch errors, • a stripped-down version of an existing such coercions are less permissive than language JavaScript 1.5’s coercions.Although many of the facilities providedimprove performance, that by itself is not 4.2 Strong Dynamic Typingtheir reason for inclusion in the language. JavaScript 2.0 is strongly typed — type declarations are enforced. On the other hand,4 Type System JavaScript 2.0 is not statically typed — the compiler does not verify that type errorsJavaScript 2.0 supports the notion of a type, cannot occur at run time. To illustrate thewhich can be thought of as a subset of all difference, consider the class definitionspossible values. There are some built-in below, which define a class A with instancetypes such as O b j e c t , Number, and variable x and a subclass B of A with an ad-String; each user-defined class (section 6) ditional instance variable y:is also a type. class A {The root of the type hierarchy is Object. var x;Every value is a member of the type }Object. Unlike in JavaScript 1.5, there isno real distinction between primitive values class B extends A { var y;and objects4. }Unlike in C and Java, types are first-classvalues. Type expressions are merely value Given the above, the following statementsexpressions that evaluate to values that are all work as expected:types; therefore, type expressions use the var a:A = new A;same syntax as value expressions. var b:B = new B; a = b; var o = new A;4.1 Type Declarations An untyped variable such as o is consideredVariables in JavaScript 2.0 can be typed us- to have type Object, so it admits everying the syntax value. The following statements, which4 would be errors in a statically typed lan- The bizarre JavaScript 1.5 dichotomy between String, guage, also execute properly because theNumber, and Boolean values and String, Number, andBoolean objects is eliminated, although an implementation run-time values being assigned are of themay preserve it as an optional language extension for com- proper type:patibility. All JavaScript 2.0 values behave as though they areobjects — they have methods and properties — althoughsome of the more important classes such as S t r i n g, 5 Actually, the rule is that successfully reading a variableNumber, etc. are final and don’t allow the creation of always returns an element of the variable’s type. This isdynamic properties, so their instances can be transparently because a variable may be in an uninitialized state, in whichimplemented as primitives. case trying to read it generates an error.JavaScript 2.0: Evolving a Language for Evolving Systems 6
  7. 7. b = a; 4.3 Rationale a = o; Why doesn’t JavaScript 2.0 support staticOn the other hand, assigning b = o gen- typing? Although this would help catch pro-erates a run-time error because o does not grammer errors, it would also dramaticallycurrently contain an instance of B. change the flavor of the language. Many of the familiar idioms would no longer work,Because JavaScript is not statically typed, and the language would need to acquire thefunction sum below also compiles correctly; concept of interfaces which would then haveit would be a compile-time error in a stati- to be used almost everywhere. Followed tocally typed language because the compiler the logical conclusion, the language wouldcould not statically prove that c will have a become nearly indistinguishable from Javaproperty named y.6 or C#; there is no need for another such lan- function sum(c:A) { guage. return c.x + c.y; } Another common question is why JavaScript 2.0 uses the colon notation forThe assignment to z1 will execute success- type annotation instead of copying the C-fully, while the assignment to z2 will gen- like syntax. Embarrassingly, this is a deci-erates a run-time error when trying to look sion based purely on a historical standardsup c.y:7 committee vote — this seemed like a good idea at one time. There is no technical rea- var z1 = sum(new B); son for using this syntax, but it’s too late to var z2 = sum(new A); reverse it now (implementations using thisThe declaration c:A inside sum is still en- syntax have already shipped), even thoughforced — it requires that the argument most of the people involved with it admit thepassed to sum must be a member of type A; syntax is a mistake.thus, an attempt to call sum on an instanceof some class C unrelated to A would gener- 5 Scoping and Strict Modeate an error even if that instance happened tohave properties x and y. JavaScript 1.5 suffers from a number of de- sign mistakes (see sections 2.1 and 2.3 forThe general principle here is that only the some examples) that are causing problems inactual run-time type of an expression’s value JavaScript 2.0. One of the problems is thatmatters — unlike statically typed languages all var declarations inside a function aresuch as C++ and Java, JavaScript 2.0 has no hoisted, which means that they take effect atconcept of the static type of an expression. the very beginning of the function even if the v a r declarations are nested inside blocks. Furthermore, duplicate var decla- rations are merged into one. This is fine for untyped variables, but what should happen6 If class A were final, a smart JavaScript compiler could for typed variables? What should the inter-issue a compile-time error for function sum because it could pretation of the following function be?prove that no possible value of c could have a property function f(a) {named y. The difference here is that a compiler for a stati-cally typed language will issue an error if it cannot prove that if (a) {the program will work without type errors. A compiler for a var b:String = g();dynamically typed language will issue an error only if it can } else {prove that the program cannot work without type errors;strong typing is ensured at run time. var b:Number = 17;7 Unlike with prototype-based objects, by default an attempt }to refer to a nonexistent property of a class instance signals }an error instead of returning undefined or creating theproperty. See section 6.JavaScript 2.0: Evolving a Language for Evolving Systems 7
  8. 8. Using JavaScript 1.5 rules would interpret variable. Moreover, if a block declares a lo-the function as the following, which would cal variable named x, then an outer block inbe an error because now b has two different the same function may not refer to a globaltypes: variable named x. Thus, the following code function f(a) { is in error because the return statement is var b:String; not permitted to refer to the global x: var b:Number; var x = 3; if (a) { b = g(); function f(a) { } else { if (a) { b = 17; var x:Number = 5; } } } return x; }JavaScript 2.0 also introduces the notion ofconst, which declares a constant ratherthan a variable. If b were a const instead 5.1 Strict Modeof a var, then even if the two declarations Some of JavaScript 1.5’s quirks can’t behad the same type then it would be undesir- corrected without breaking compatibility.able to hoist it: For these JavaScript 2.0 introduces the no- function f(a) { tion of a strict mode which turns off some of if (a) { the more troublesome behavior. In addition const b = 5; to making all declarations lexically scoped, } else { strict mode does the following: const b = 17; • Variables must be declared — mis- } spelled variables no longer automati- } cally create new global variables.should not become: • Function declarations are immutable function f(a) { (JavaScript 1.5 treats any function dec- const b; laration as declaring a variable that may if (a) { be replaced by another function or any b = 5; other value at any time). } else { b = 17; • Function calls are checked to make sure } that they provide the proper number of } arguments. JavaScript 2.0 provides an explicit way of declaring functions thatFor one thing, the latter allows b to be refer- take optional, named, or variableenced after the end of the if statement. amounts of arguments.To solve these problems while remaining • Semicolon insertion changes — linecompatible with JavaScript 1.5, Java- breaks are no longer significant in strict-Script 2.0 adopts block scoping with one mode JavaScript 2.0 source code. Lineexception: var declarations without a type breaks no longer turn into semicolonsand in non-strict mode (see below) are still (as they do in some places inhoisted to the top of a function. var decla- JavaScript 1.5), and they are nowrations with a type are not hoisted, const allowed anywhere between two tokens.declarations are not hoisted, and declarations Strict and non-strict parts may be mixedin strict mode are not hoisted. To help catch freely within a program. For compatibility,errors, a block nested inside another block the default is non-strict mode.within a function may not redeclare a localJavaScript 2.0: Evolving a Language for Evolving Systems 8
  9. 9. 6 Classes enforce these rules without cooperation from its clients, which allows well-con-In addition to the prototype-based objects of structed classes to rely on their invari-JavaScript 1.5, JavaScript 2.0 supports class- ants regardless of what their clients do.based objects. Class declarations are best • Classes provide a good basis forillustrated by an example: versioning and access control (sec- class Point { tion 7). var x:Number; • Prototype-based languages naturally var y:Number; evolve classes anyway by convention, typically by introducing dual hierarchies function radius() { that include prototype and traits objects return Math.sqrt( [1]. Placing classes in the language x*x + y*y); makes the convention uniform and en- } forceable.8 • Complexity of prototypes. Few scrip- static var count = 0; ters are sophisticated enough to cor- } rectly create a multi-level prototype- based hierarchy in JavaScript 1.5. InA class definition is like a block in that it fact, this is difficult even for moderatelycan contain arbitrary statements that are experienced programmers.evaluated at the time execution reaches the • The class syntax is much more self-class; however, definitions inside the class documenting than analogous Java-define instance (or class if preceded with the Script 1.5 prototype hierarchies.static attribute) members of the class in- • Classes as a primitive in the languagestead of local variables. Classes can inherit provide a valuable means of reflectingfrom other classes, but multiple inheritance other languages’ data structures inis not supported. JavaScript 2.0 and vice versa.Classes can co-exist with prototype-based • Classes are one of the most-requestedobjects. The syntax to read or write a prop- features in JavaScript.erty (object.property) is the same regardlessof whether the object is prototype or class- Introducing two means of doing somethingbased. By default, accessing a nonexistent (classes and prototypes) always carries someproperty of a class instance is an error, but if burden of having to choose ahead of timeone places the attribute dynamic in front which means to use for a particular problem and the subsequent danger of needing to re-of the class declaration then one can create cover from having made the wrong choice.new dynamic properties on that class’s in- However, it’s likely that at some point in thestances just like for prototype-based objects. future most programmers will use classes exclusively and not even bother to learn6.1 Rationale prototypes. To make recovery easier, theThere are a number of reasons classes were syntax for routine usage of classes and pro-added to JavaScript 2.0: totypes is identical, so changing one to the other only requires changing the declaration. • Classes provide stronger and more flexible abstractions than prototypes. A 8 An earlier JavaScript 2.0 proposal actually reflected a class can determine the pattern of mem- class’s members via prototypes and traits objects and allowed bers that each instance must have, con- any class instance to serve as a base for prototype inheritance and vice versa. That proposal was dropped because it made trol the creation of instances, and control language implementation much more complex than desired both its usage and overriding interfaces. and required the authors of classes to think about not only Furthermore, a JavaScript 2.0 class can constructors but also cloners just in the rare case that a client used the classes’ instances as prototypes.JavaScript 2.0: Evolving a Language for Evolving Systems 9
  10. 10. To keep the language simple, there is no no- 7.3 Scenariotion of Java-like interfaces. Unlike in Java,these are not necessary for polymorphism Here’s an example of how such a collisionbecause JavaScript 2.0 is dynamically typed. can arise. Suppose that a package provider creates a package called BitTracker that exports a class Data. This package be-7 Namespaces, Versioning, comes so successful that it is bundled with all web browsers produced by the Brows-and Packages ersRUs company: package BitTracker {7.1 Packages class Data {A JavaScript 2.0 package is a collection of var author;top-level definitions declared inside a var contents;package statement. An import statement function save() {...}refers to an existing package and makes the }top-level definitions from that packageavailable. The exact scheme used to name function store(d) {and locate existing packages is necessarily ...dependent on the environment in which storeOnFastDisk(d);JavaScript 2.0 is embedded and will be de- }fined and standardized independently as }needed for each kind of embedding (brows-ers, servers, standalone implementations, Now someone else writes a client web pageetc.). W that takes advantage of BitTracker. The class Picture derives from Data and7.2 Versioning Issues adds, among other things, a method called size that returns the dimensions of theAs a package evolves over time it often be- picture:comes necessary to change its exported in- import BitTracker;terface. Most of these changes involve add-ing definitions (top-level or class members), class Picture extendsalthough occasionally a definition may be Data {deleted or renamed. In a monolithic envi- function size() {...}ronment where all JavaScript source code var palette;comes preassembled from the same source, };this is not a problem. On the other hand, ifpackages are dynamically linked from sev- function orientation(d) {eral sources then versioning problems are if (d.size().h >=likely to arise. d.size().v) return "Landscape";One of the most common avoidable prob- elselems is collision of definitions. Unless this return "Portrait";problem is solved, an author of a package }will not be able to add even one definition ina future version of his package because that The author of the BitTracker package,definition’s name could already be in use by who hasn’t seen W, decides in response tosome client or some other package that a customer requests to add a method calledclient also links with. This problem occurs size that returns the number of bytes ofboth in the global scope and in the scopes of data in a Data object. He then releases theclasses from which clients are allowed to new and improved BitTracker package.inherit.JavaScript 2.0: Evolving a Language for Evolving Systems 10
  11. 11. BrowsersRUs includes this package with its originates. Unfortunately, this would getlatest Navigator 17.0 browser: tedious and unnecessarily impact casual uses of the language. Furthermore, this package BitTracker { approach is impractical for names of class Data { methods because it is often desirable to var author; share the same method name across sev- var contents; eral classes to attain polymorphism; this function size() {...} would not be possible if Netscape’s ob- jects used com_netscape_length function save() {...} } while MIT’s objects all used edu_mit_length. function store(d) { • Explicit imports. Each client package ... could be required to import every exter- if (d.size() > limit) nal name it references. This works rea- storeOnSlowDisk(d); sonably well for global names but be- else comes tedious for the names of class storeOnFastDisk(d); members, which would have to be im- } ported separately for each class. } • Resolve names at compile time. JavaAn unsuspecting user U upgrades his old and C# resolve the references of namesBrowsersRUs browser to the latest Naviga- to the equivalents of vtable slots at com-tor 17.0 browser and a week later is dis- pile time. This way size inside storemayed to find that page W doesn’t work can resolve to something other thananymore. U’s grandson tries to explain to U size inside orientation. Unfortu-that he’s experiencing a name conflict on the nately, this approach works only forsize methods, but U has no idea what the statically typed languages. Moreover,kid is talking about. U attempts to contact this approach relies on object codethe author of W, but she has moved on to rather than source code being distributedother pursuits and is on a self-discovery — the ambiguity is still present in themission to sub-Saharan Africa. Now U is source code, and it is only the extra datasteaming at BrowsersRUs, which in turn is inserted by past compilation of the clientpointing its collective finger at the author of against an older version of the packageBitTracker. that resolves it. • Versions. Package authors could markNote that this name collision occurs inside a the names they export with explicit ver-class and is much more insidious than sions. A package’s developer could in-merely a conflict among global declarations troduce a new version of the packagefrom imported packages. with additional names as long as those names were made invisible to clients7.4 Solutions expecting to link with prior versions.How could the author of BitTracker JavaScript 2.0 follows the last approach. It ishave avoided this problem? Simply choos- the most desirable because it places theing a name other than size wouldn’t work, smallest burden on casual users of the lan-because there could be some other page W2 guage, who merely have to import the pack-that conflicts with the new name. There are ages they use and supply the current versionseveral possible approaches: numbers in the import statements. A pack- age author has to be careful not to disturb • Naming conventions. Each defined the set of visible prior-version definitions name could be prefixed by the full name of the party from which this definition when releasing an updated package, butJavaScript 2.0: Evolving a Language for Evolving Systems 11
  12. 12. authors of dynamically linkable packages package BitTracker {tend to be much more sophisticated thancasual users of the language. explicit namespace v2; use namespace(v2);7.5 Namespaces class Data {JavaScript 2.0 employs namespaces to pro- var author;vide safe versioning. A package can define var contents;and export several namespaces, each of v2 function size() {...}which provides a different view of the pack- function save() {...}age’s contents. Each namespace corresponds }to a version of the package’s API. function store(d) {A JavaScript 2.0 namespace is a first-class ...value that is merely a unique token and has if (d.size() > limit)no members, internal structure, or inheri- storeOnSlowDisk(d);tance. JavaScript namespaces are not related elseto C++ namespaces. On the other hand, the storeOnFastDisk(d);designers of other dynamic languages such }as Smalltalk have independently run into the }same versioning problem and come up witha solution similar to JavaScript 2.0’s (for If the client W isn’t updated, then it will notexample, “Selector Namespaces” in [10]). be aware that BitTracker’s size exists and will be able to refer to its own sizeEach JavaScript 2.0 name is actually an or- method. If the author of W later wants todered pair namespace::identifier, where revise her web page to also refer ton a m e s p a c e is a simple expression that BitTracker’s size, then she can eitherevaluates to a namespace value. When a explicitly refer to v2::size or rename hername is defined without a namespace, the size to some other name and then importnamespace defaults to the predefined name- v2.9space public.A use namespace(n) statement allows 7.6 Private and Internalunqualified access within a scope to identifi-ers qualified with namespace n. There is an In addition to providing access controlimplicit use namespace(public) among packages, namespaces also workstatement around the whole program. For well within a package. In fact, early in theconvenience, a namespace may also be development of JavaScript 2.0 it becamespecified when importing a package. apparent that the notions of private and internal (visible inside a package only)Given namespaces, the author of are simply special cases of namespaces.B i t T r a c k e r can release the updated Each class has a predefined p r i v a t epackage while hiding the size method namespace that can be referenced using thefrom existing clients that don’t expect to see private keyword inside that class and thatit: 9 This description is glossing over how the author of BitTracker keeps the name of the namespace itself v2 from colliding with some other global definition inside the client W. The basic explanation is that the explicit attrib- ute keeps v2 itself from being imported by default. If a client knows that v2 is there and won’t cause a conflict, then it can explicitly request v2 to be imported; there is a convenient syntax for doing that using an import statement. See [7] for the details.JavaScript 2.0: Evolving a Language for Evolving Systems 12
  13. 13. is use’d only inside that class. Different class A {classes have independent private name- N function f()spaces. {return "fA"} }Namespaces offer a finer granularity ofpermissions — a class can have some class B extends A {private members visible only to itself, N function f()but it can also define members defined in a {return "fB"}custom namespace visible to some but not }all of its users. class C extends B { public function f()7.7 Property Lookup {return "fC"} }Namespaces control the behavior of lookingup either a qualified property n::p or an c = new C;unqualified property p of an object o. It mayappear that there are many ways of defining Now, if one calls c.f(), the result ought tothis lookup process, but in fact only one way depend on whether aallows for reliable versioning. The resulting use namespace(N) is lexically in effectlookup process appears counterintuitive at around the expression c.f(). If it is not,first but is in fact the correct one and de- then the behavior is simple — only the fserves a closer look. defined by C is visible, so once again the result is "fC".The process is illustrated by a few examples.Consider first the simple case of a hierarchy If use namespace(N) is lexically inof three classes: effect around the expression c.f(), then class A { all three definitions of f are visible. It would public function f() be tempting to choose the most derived one {return "fA"} ("fC"), but this would be incorrect because: } • This is analogous to the BitTracker class B extends A { scenario. Class C might have defined public function f() function f first and classes A and B later {return "fB"} evolved to define their own, hidden f. } To make this work, any code in the lexi- cal scope of a use namespace(N) class C extends B { public function f() must not have its meaning hijacked by {return "fC"} anything class C does. } • Suppose that N is p r i v a t e or internal instead. Class C ought not c = new C; to be able to override a private orIf one calls c.f(), one would expect to, internal method, which might leadand does in fact, get "fC", the most derived to an object security violation.definition of f. This is the essence of object- Other solutions such as signaling an ambi-oriented semantics. guity error when encountering the expres- sion c.f() or alternately even preventingNow let’s alter the example by putting A and class C from being defined are also incorrectB’s definitions of f into a namespace N: for the same reasons as above.JavaScript 2.0: Evolving a Language for Evolving Systems 13
  14. 14. The only sensible thing to do is to define the several qualified names, one for each name-language so that the expression c.f() in space, which is valuable for manythis case returns "fB". The rule for looking versioning scenarios.up an unqualified property p of an object o Attributes may be placed before the openingis therefore: braces of a block, which distributes the at- • First, find the highest (least derived) tributes among all the definitions inside that class that defines a property of o named block. Thus, instead of p that’s visible in the currently used class A { namespaces; let n be that member’s static private const x; namespace (if there is more than one static private const y; such namespace in the same class, just static private const z; pick one). function f() {} • Second, find and return the lowest (most } derived) definition of o.n::p. one can write:The rule for looking up a qualified property class A {n::p of an object o is the same as in object- static private { const x;oriented programming — return the lowest const y;(most derived) definition of o.n::p. Thus, const z;in the example above c.public::f() }will return " f C " regardless of the function f() {}use namespace declarations in effect. }Perhaps not coincidentally, defining the Two other very useful attributes are truerules this way makes JavaScript 2.0 much and false. The attribute true is ignored.easier to compile by allowing partial false causes the entire definition or state-evaluation of property lookups in many ment to disappear without being evaluatedcommon cases. or processed further. By defining a global boolean constant (or obtaining one from the environment) one can achieve convenient8 Attributes and conditional compilation without resorting toConditional Compilation a separate preprocessor language. In the ex- ample below, instances of class A have theSeveral of the previous sections implicitly slot c o u n t and method g only if thereferenced attributes. This section explores const definition of debug is changed tothem in a little more detail and uncovers an true:interesting and perhaps unexpected use of const debug = false;attributes for conditional compilation. class A {In JavaScript 2.0, attributes are simple con- var x;stant expressions that can be listed in front debug var count;of most definitions as well as a few otherstatements. Examples of attributes already function f() {}mentioned include s t a t i c , public, debug function g() {}private, explicit, dynamic, final, }as well as namespaces. These are, in fact,constant expressions, and other attributesmay be defined using const definitions. 9 ConclusionMultiple attributes may be listed on thesame definition. Attaching multiple name- This paper presents only the highlights andspaces to a definition simultaneously defines some of the rationale of JavaScript 2.0.JavaScript 2.0: Evolving a Language for Evolving Systems 14
  15. 15. There are a few other features, such as units, hoc and especially complicated. Trying totyped arrays, and operator overriding that avoid complexity while retaining compati-were not covered here. See [7] for a much bility has been a constant struggle.more detailed description. Netscape’s implementations [8] ofIt’s been a long road to get to this point, JavaScript 1.5 and the forthcoming 2.0 arewith various proposals being discussed in available as open source under the NPL,the ECMA TC39 working group for several GPL, or LGPL license. The JavaScriptyears. Most of what made the problem so source code is compact and stand-alone anddifficult and time-consuming is the difficult does not depend on the rest of the browser totask of retaining backward compatibility. be compiled; it’s been embedded inJavaScript 1.5 has grown many ad-hoc fea- hundreds if not thousands of differenttures that don’t carry forward well and tend environments to date.to make any future evolution even more ad-Bibliography [1] Martin Abadi, Luca Cardelli. A Theory of Objects. Springer-Verlag 1996. [2] ECMA web site, http://www.ecma.ch/ [3] ECMA-262 Edition 1 standard, http://www.mozilla.org/js/language/E262.pdf [4] ECMA-262 Edition 2 standard, http://www.mozilla.org/js/language/E262-2.pdf [5] ECMA-262 Edition 3 standard, http://www.mozilla.org/js/language/E262-3.pdf [6] David Flanagan. JavaScript: The Definitive Guide, 4th Edition. O’Reilly 2002. [7] Mozilla’s JavaScript 2.0 web site, http://www.mozilla.org/js/language/js20/ [8] Mozilla’s JavaScript web site, http://www.mozilla.org/js/ [9] Netscape. Object Hierarchy and Inheritance in JavaScript. Thunder Lizard Productions JavaScript Conference ’98, also available at http://developer.netscape.com/docs/manuals/communicator/jsobj /index.htm[10] SmallScript LLC. SmallScript Website, http://www.smallscript.net/[11] W3C Document Object Model, http://www.w3.org/DOM/JavaScript 2.0: Evolving a Language for Evolving Systems 15