0% found this document useful (0 votes)
16 views24 pages

Scala Overview

Scala is a statically typed programming language that unifies object-oriented and functional programming. It aims to support the construction of components and component systems. The Scala language fuses object-oriented and functional programming in a way that generalizes and unifies the two paradigms. It is designed to work well with existing platforms and components like Java and C#, while also introducing new concepts like abstract type definitions, path-dependent types, symmetric mixin composition, and views.

Uploaded by

peter ivanov
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views24 pages

Scala Overview

Scala is a statically typed programming language that unifies object-oriented and functional programming. It aims to support the construction of components and component systems. The Scala language fuses object-oriented and functional programming in a way that generalizes and unifies the two paradigms. It is designed to work well with existing platforms and components like Java and C#, while also introducing new concepts like abstract type definitions, path-dependent types, symmetric mixin composition, and views.

Uploaded by

peter ivanov
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

An Overview of the Scala Programming Language

Martin Odersky, Philippe Altherr, Vincent Cremet, Burak Emir, Sebastian Maneth,

Stéphane Micheloud, Nikolay Mihaylov, Michel Schinz, Erik Stenman, Matthias Zenger

École Polytechnique Fédérale de Lausanne


1015 Lausanne, Switzerland

Technical Report IC/2004/64

Abstract language which unies and generalizes object-oriented and


functional programming. For statically typed languages, of
Scala fuses object-oriented and functional programming in which Scala is an instance, these two paradigms were up to
a statically typed programming language. It is aimed at the now largely separate.
construction of components and component systems. This To validate our hypotheses, Scala needs to be applied
paper gives an overview of the Scala language for readers in the design of components and component systems. Only
who are familar with programming methods and program- serious application by a user community can tell whether the
ming language design. concepts embodied in the language really help in the design
of component software. To ease adoption by users, the new

1 Introduction language needs to integrate well with existing platforms and


components. Scala has been designed to work well with
Java and C#. It adopts a large part of the syntax and type
True component systems have been an elusive goal of the
systems of these languages. At the same time, progress can
software industry. Ideally, software should be assembled
sometimes only be achieved by throwing over board some
from libraries of pre-written components, just as hardware is
existing conventions. This is why Scala is not a superset of
assembled from pre-fabricated chips. In reality, large parts
Java. Some features are missing, others are re-interpreted
of software applications are written from scratch, so that
to provide better uniformity of concepts.
software production is still more a craft than an industry.
While Scala's syntax is intentionally conventional, its
Components in this sense are simply software parts which
type system breaks new ground in at least three areas. First,
are used in some way by larger parts or whole applications.
Components can take many forms; they can be modules,
abstract type deninitions and path-dependent types apply
the ν Obj calculus [35] to a concrete language design. Sec-
classes, libraries, frameworks, processes, or web services.
Their size might range from a couple of lines to hundreds of
ond, symmetric mixin composition combines the advantages
thousands of lines. They might be linked with other compo-
of mixins and traits. Third,views enable component adap-
tation in a modular way.
nents by a variety of mechanisms, such as aggregation, pa-
The rest of this paper gives an overview of Scala. It
rameterization, inheritance, remote invocation, or message
expands on the following key aspects of the language:
passing.
We argue that, at least to some extent, the lack of ˆ Scala programs resemble Java programs in many ways
progress in component software is due to shortcomings in the and they can seamlessly interact with code written in
programming languages used to dene and integrate compo- Java (Section 2).
nents. Most existing languages oer only limited support for
component abstraction and composition. This holds in par- ˆ Scala has a uniform object model, in the sense that
ticular for statically typed languages such as Java and C# every value is an object and every operation is a method
in which much of today's component software is written. call (Section 3).
Scala has been developed between 2001 and 2004 in the
programming methods laboratory at EPFL. It stems from a
ˆ Scala is also a functional language in the sense that
functions are rst-class values (Section 4).
research eort to develop better language support for com-
ponent software. There are two hypotheses that we would
ˆ Scala has uniform and powerful abstraction concepts
like to validate with the Scala experiment. First, we postu-
for both types and values (Section 5).
late that a programming language for component software
needs to be scalable in the sense that the same concepts can ˆ It has exible symmetric mixin-composition constructs
describe small as well as large parts. Therefore, we con- for composing classes and traits (Section 6).
centrate on mechanisms for abstraction, composition, and
decomposition rather than adding a large set of primitives ˆ It allows decomposition of objects by pattern matching
which might be useful for components at some level of scale, (Section 7).
but not at other levels. Second, we postulate that scalable
ˆ Patterns and expressions are generalized to support the
support for components can be provided by a programming
natural treatment of XML documents (Section 8).
ˆ Scala does not have special syntax for array types and
// Java array accesses. An array with elements of type T is
class PrintOptions { written Array[T ]. Here, Array is a standard class and
public static void main(String[] args) { [T ] is a type parameter. In fact, arrays in Scala inherit
System.out.println("Options selected:"); 1
from functions . This is why array accesses are written
for (int i = 0; i < args.length; i++) like function applications a(i), instead of Java's a[i].
if (args[i].startsWith("-"))
System.out.println(" "+args[i].substring(1)); ˆ The return type of main is written unit whereas Java
} uses void. This stems from the fact that there is no dis-
} tinction in Scala between statements and expressions.
Every function returns a value. If the function's right
// Scala hand side is a block, the evaluation of its last expression
object PrintOptions { is returned as result. The result might be the trivial
def main(args: Array[String]): unit = { value {} whose type is unit. Familar control constructs
System.out.println("Options selected:"); such as if-then-else are also generalized to expressions.
for (val arg <- args)
if (arg.startsWith("-")) ˆ Scala adopts most of Java's control structures, but it
System.out.println(" "+arg.substring(1)); lacks Java's traditional for-statement. Instead, there
} are for-comprehensions which allow one to iterate di-
} rectly over the elements of an array (or list, or iter-
ator, ...) without the need for indexing. The new
Listing 1: A simple program in Java and Scala.
Java 1.5 also has a notion of extended for-loop which
is similar to, but more restrictive than, Scala's for-
comprehensions.

ˆ Taken together, these constructs make it easy to ex- Even though their syntax is dierent, Scala programs can
press autonomous components using Scala libraries inter-operate without problems with Java programs. In
without need for special language constructs (Sec- the example above, the Scala program invokes methods
tion 9). startsWith and substring of String, which is a class de-
ned in Java. It also accesses the static out eld of the Java
ˆ Scala allows external extensions of components using class System, and invokes its (overloaded) println method.
views (Section 10). This is possible even though Scala does not have a concept
of static class members. In fact, every Java class is seen in
ˆ Scala is currently implemented on the Java (Section 11)
Scala as two entities, a class containing all dynamic mem-
and .NET (Section 12) platforms.
bers and a singleton object, containing all static members.
Section 13 discusses related work and Section 14 concludes. Hence, System.out is accessible in Scala as a member of the
object System.
2 A Java-Like Language Even though it is not shown in the example, Scala classes
and objects can also inherit from Java classes and implement
Java interfaces. This makes it possible to use Scala code in
Scala is designed to interact well with mainstream platforms
such as Java or C#. It shares with these languages most of
a Java framework. For instance, a Scala class might be de-

the basic operators, data types, and control structures.


ned to implement the interface java.util.EventListener.
Instances of that class may then be notied of events issued
For simplicity, we compare Scala in the following only
by Java code.
with Java. But since Java and C# have themselves much
in common, almost all similarities with Java carry over to
C#. Sometimes, Scala is even closer to C# than to Java,
for instance in its treatment of genericity.
3 A Unied Object Model
Listing 1 shows a simple program in Java and Scala. The Scala uses a pure object-oriented model similar to
program prints out all options included in the program's Smalltalk's: Every value is an object and every operation
command line. The example shows many similarities. Both is a message send.
languages use the same primitive class String, calling the
same methods. They also use the same operators and the
same conditional control construct. The example also shows
3.1 Classes
some dierences between the two languages. In particular: Figure 3.1 illustrates Scala's class hierarchy. Every class in
Scala inherits from class Scala.Any. Subclasses of Any fall
ˆ Scala has object denitions (starting with object) be-
sides class denitions. An object denition denes a
into two categories: the value classes which inherit from
scala.AnyVal and the reference classes which inherit from
class with a single instance  this is sometimes called
scala.AnyRef. Every primitive Java type name corresponds
a singleton object. In the example above, the singleton
to a value class, and is mapped to it by a predened type
object PrintOptions has main as a member function.
alias. In a Java environment, AnyRef is identied with the
ˆ Scala uses the id : type syntax for denitions and pa- root class java.lang.Object. An instance of a reference
rameters whereas Java uses prex types, i.e. type id. class is usually implemented as a pointer to an object stored
in the program heap. An instance of a value class is usually
ˆ Scala's syntax is more regular than Java's in that all
represented directly, without indirection through a pointer.
denitions start with a keyword. In the example above,
def main starts a method denition. 1 Arrays are further explained in Section 4.3.

2
Sometimes it is necessary to convert between the two repre- Scala treats operator names as ordinary identiers. More
sentations, for example when an instance of a value class is precisely, an identier is either a sequence of letters and
seen as an instance of the root class Any. These boxing con- digits starting with a letter, or a sequence of operator char-
versions and their inverses are done automatically, without acters. Hence, it is possible to dene methods called +, <=,
explicit programmer code. or ::, for example. Next, Scala treats every occurrence of
Note that the value class space is at; all value classes an identier between two expressions as a method call. For
are subtypes from scala.AnyVal, but they do not subtype instance, in Listing 1, one could have used the operator syn-
each other. Instead there are views (i.e. standard coercions, tax (arg startsWith "-") as syntactic sugar for the more
see Section 10) between elements of dierent value classes. conventional syntax (arg.startsWith("-")).
We considered a design alternative with subtyping between As an example how user-dened operators are declared
value classes. For instance, we could have made Int a sub- and applied, consider the following implementation of a
type of Float, instead of having a standard coercion from class Nat for natural numbers. This class (very ine-
Int to Float. We refrained from following this alternative, Zero
ciently) represents numbers as instances of two classes
because we want to maintain the invariant that interpreting and Succ. The number N would hence be represented as
a value of a subclass as an instance of its superclass does not new SuccN (Zero). We start the implementation with a trait
change the value's representation. Among other things, we specifying the interface of natural numbers. For now, traits
want to guarantee that for each pair of types S <: T and can be seen as abstract classes; details are given later in
2
each instance x of S the following equality holds : Nat, natural
Section 6.2. According to the denition of trait
numbers provide two abstract methods isZero, and pred, as
x.asInstanceOf[T].asInstanceOf[S] = x well as three concrete methods succ, +, and -.

At the bottom of the type hierarchy are the two classes trait Nat {
scala.AllRef and scala.All. Type AllRef is a subtype of def isZero: boolean;
all reference types; its only instance is the null reference. def pred: Nat;
Since AllRef is not a subtype of value types, null is not a def succ: Nat = new Succ(this);
member of any such type. For instance, it is not possible to def + (x: Nat): Nat =
assign null to a variable of type int. if (x.isZero) this else succ + x.pred;
Type All is a subtype of every other type; there exist no def - (x: Nat): Nat =
instances of this type. Even though type All is empty, it is if (x.isZero) this else pred - x.pred;
nevertheless useful as a type parameter. For instance, the }
Scala library denes a value Nil of type List[All]. Because
lists are covariant in Scala, this makes Nil an instance of Note that Scala allows one to dene parameterless methods
List[T ], for any element type T . such as isZero, pred, and succ in class Nat. Such methods
The equality operation == between values is designed to are invoked every time their name is selected; no argument
be transparent with respect to the type's representation. For list is passed. Note also that abstract class members are
value types, it is the natural (numeric or boolean) equality. identied syntactically because they lack a denition; no
For reference types, == is treated as an alias of the equals additional abstract modier is needed for them.
method from java.lang.Object. That method is originally We now extend trait Nat with a singleton object Zero
dened as reference equality, but is meant to be overridden and a class for representing successors, Succ.
in subclasses to implement the natural notion of equality for
object Zero extends Nat {
these subclasses. For instance, the boxed versions of value
def isZero: boolean = true;
types would implement an equals method which compares
def pred: Nat = throw new Error("Zero.pred");
the boxed values. By contrast, in Java, == always means ref-
}
erence equality on reference types. While this is a bit more
class Succ(n: Nat) extends Nat {
ecient to implement, it also introduces a serious coherence
def isZero: boolean = false;
problem because boxed versions of equal values might no
def pred: Nat = n;
longer be equal (with respect to ==).
}
Some situations require reference equality instead of
user-dened equality. An example is hash-consing, where The Succ class illustrates a dierence between the class def-
eciency is paramount. For these cases, class AnyRef de- inition syntax of Scala and Java. In Scala, constructor pa-
nes an additional eq method, which cannot be overridden, rameters follow the class name; no separate class constructor
and is implemented as reference equality (i.e., it behaves like denition within the body of Succ is needed. This construc-
== in Java for reference types). tor is called the primary constructor ; the whole body of the
class is executed when the primary constructor is called at
3.2 Operations the time the class is instantiated. There is syntax for sec-
ondary constructors in case more than one constructor is
Another aspect of Scala's unied object model is that ev- desired (see Section 5.2.1 in [34]).
ery operation is a message send, that is, the invocation of The ability to have user-dened inx operators raises
a method. For instance the addition x + y is interpreted as the question about their relative precedence and associativ-
x.+(y), i.e. the invocation of the method + with x as the ity. One possibility would be to have xity-declarations in
receiver object and y as the method argument. This idea, the style of Haskell or SML, where users can declare these
which has been applied originally in Smalltalk, is adapted properties of an operator individually. However, such decla-
to the more conventional syntax of Scala as follows. First, rations tend to interact badly with modular programming.
2 asInstanceOf is Scala's standard type cast method dened in the
Scala opts for a simpler scheme with xed precedences and
root class Any. associativities. The precedence of an inx operator is deter-

3
scala.Any Subtype
View

scala.AnyVal scala.AnyRef
(java.lang.Object)

scala.Double
scala.Unit scala.ScalaObject

scala.Float scala.Boolean
scala.Iterable java.lang.String

scala.Long scala.Char
scala.Seq scala.Symbol
… (other Java classes)…
scala.Int
scala.Ordered
scala.List

… (other Scala classes)…


scala.Short

scala.Byte scala.AllRef

scala.All

Figure 1: Class hierarchy of Scala.

mined by its rst character; it coincides with the operator ||. Such operators can also be represented as methods be-
precedence of Java for those operators that start with an cause Scala allows to pass arguments by name. For instance,
operator character used in these languages. The following here is a user-dened trait Bool that mimics the pre-dened
lists operators in increasing precedence: booleans.

(all letters) trait Bool {


| def && (def x: Bool): Bool;
^ def || (def x: Bool): Bool;
& }
< >
= ! In this trait, the formal parameter of methods || and && is
: prexed by def. The actual arguments for these parameters
+ - are passed in unevaluated form. The arguments are eval-
/ % uated every time the formal parameter name is mentioned
*
(all other special characters) (that is, the formal parameter behaves like a parameterless
function).
Operators are usually left-associative, i.e. x + y + z is Here are the two canonical instances of class Bool:
interpreted as (x + y) + z. The only exception to that
rule are operators ending in a colon. These are treated as object False extends Bool {
right-associative. An example is the list-consing operator def && (def x: Bool): Bool = this;
::. Here, x :: y :: zs is interpreted as x :: (y :: zs). def || (def x: Bool): Bool = x;
Right-associative operators are also treated dierently with }
respect to method lookup. Whereas normal operators take object True extends Bool {
their left operand as receiver, right-associative operators def && (def x: Bool): Bool = x;
take their right operand as receiver. For instance, the list
def || (def x: Bool): Bool = this;
consing sequence x :: y :: zs is treated as equivalent to
}
zs.::(y).::(x). In fact, :: is implemented as a method in
As can be seen in these implementations, the right operand
Scala's List class, which prexes a given argument to the
of a && (resp. ||) operation is evaluated only if the left
receiver list and returns the resulting list as result.
operand is the True (False) object.
Some operators in Scala do not always evaluate their ar-
As the examples in this section show, it is possible in
gument; examples are the standard boolean operator && and
Scala to dene every operator as a method and treat every

4
operation as an invocation of a method. In the interest of functions as arguments, or return them as results, are called
eciency, the Scala compiler translates operations on value higher-order functions.
types directly to primitive instruction codes; this, however, Once we have a function exists, we can use it to dene
is completely transparent to the programmer. a function forall by double negation: a predicate holds for
all values of an array if there does not exist an element for

3.3 Variables and Properties which the predicate does not hold. This is expressed by the
following function forall:
If every operation is a method invocation in Scala, what
about variable dereferencing and assignment? In fact, when def forall[T](xs: Array[T], p: T => boolean) = {
acting on class members these operations are also treated as def not_p(x: T) = !p(x);
method calls. For every denition of a variable var x: T in !exists(xs, not_p)
a class, Scala denes setter and getter methods as follows. }

def x: T ; The function forall denes a nested function not_p which


def x_= (newval: T ): unit; negates the parameter predicate p. Nested functions can
access parameters and local variables dened in their en-
These methods reference and update a mutable memory cell, vironment; for instance not_p accesses forall's parameter
which is not accessible directly to Scala programs. Every p.
mention of the name x in an expression is then a call to the It is also possible to dene a function without giving it a
parameterless method x. Furthermore, every assignment name; this is used in the following shorter version of forall:
x = e is interpreted as a method invocation x_=(e).
The treatment of variable accesses as method calls makes def forall[T](xs: Array[T], p: T => boolean) =
it possible to dene properties (in the C# sense) in Scala. !exists(xs, x: T => !p(x));
For instance, the following classCelsius denes a property
Here,x: T => !p(x) denes an anonymous function which
degree which can be set only to values greater or equal than
maps its parameterx of type T to !p(x).
-273.
Using exists and forall, we can dene a function
class Celsius { hasZeroRow, which tests whether a given two-dimensional
private var d: int = 0; integer matrix has a row consisting of only zeros.
def degree: int = d;
def hasZeroRow(matrix: Array[Array[int]]) =
def degree_=(x: int): unit = if (x >= -273) d = x
exists(matrix, row: Array[int] => forall(row, 0 ==));
}
The expression forall(row, 0 ==) tests whether row con-
Clients can use the pair of methods dened by class Celsius
sists only of zeros. Here, the == method of the number 0 is
as if it dened a variable:
passed as argument corresponding to the predicate parame-
val c = new Celsius; c.degree = c.degree - 1 ter p. This illustrates that methods can themselves be used
as values in Scala; it is similar to the delegates concept in
C#.

4 Operations Are Objects


4.2 Functions are Objects
Scala is a functional language in the sense that every func-
If methods are values, and values are objects, it follows
tion is a value. It provides a lightweight syntax for the
that methods themselves are objects. In fact, the syn-
denition of anonymous and curried functions, and it also
tax of function types and values is just syntactic sugar
supports nested functions.
for certain class types and class instances. The function
type S => T is equivalent to the parameterized class type
4.1 Methods are Functional Values scala.Function1[S , T ], which is dened as follows in the
standard Scala library:
To illustrate the use of functions as values, consider a func-
tion exists that tests whether a given array has an element package scala;
which satises a given predicate: trait Function1[-S, +T] {
def apply(x: S): T
def exists[T](xs: Array[T], p: T => boolean) = {
}
var i: int = 0;
while (i < xs.length && !p(xs(i))) i = i + 1; Analogous conventions exist for functions with more
i < xs.length than one argument. In general, the n-ary func-
} tion type, (T1 , T2 , ..., Tn ) => T is interpreted as
Functionn[T1 , T2 , ..., Tn , T ]. Hence, functions are in-
The element type of the array is arbitrary; this is expressed
terpreted as objects with apply methods. For example, the
by the type parameter [T] of method exists (type param-
anonymous incrementer function x: int => x + 1 would
eters are further explained in Section 5.1). The predicate
be expanded to an instance of Function1 as follows.
to test is also arbitrary; this is expressed by the parame-
terp of method exists. The type of p is the function type new Function1[int, int] {
T => boolean, which has as values all functions with domain def apply(x: int): int = x + 1
T and range boolean. Function parameters can be applied }
just as normal functions; an example is the application of
p in the condition of the while-loop. Functions which take

5
Conversely, when a value of a function type is applied to def sqrts(xs: List[double]): List[double] =
some arguments, the type's apply method is implicitly in- xs filter (0 <=) map Math.sqrt;
serted. E.g. for p of type Function1[S , T ], the application
p(x) is expanded to p.apply(x). Note that Math.sqrt comes from a Java class. Such methods
can be passed to higher-order functions in the same way as
methods dened in Scala.
4.3 Rening Functions
Since function types are classes in Scala, they can be fur- 4.5 For Comprehensions
ther rened in subclasses. An example are arrays, which are
Scala oers special syntax to express combinations of cer-
treated as special functions over the integer domain. Class
Array[T] inherits from Function1[int, T], and adds meth- tain higher-order functions more naturally. For comprehen-
ods for array update and array length, among others:
sions are a generalization of list comprehensions found in
languages like Haskell. With a for comprehension the sqrts
package scala; function can be written as follows:
class Array[T] extends Function1[int, T] {
def apply(index: int): T = ...; def sqrts(xs: List[double]): List[double] =
def update(index: int, elem: T): unit= ...; for (val x <- xs; 0 <= x) yield Math.sqrt;
def length: int = ...;
Here, val x <- xs is a generator, which produces a sequence
def exists(p: T => boolean): boolean = ...;
of values, and 0 <= x is a lter, which eliminates some of
def forall(p: T => boolean): boolean = ...;
the produced values from consideration. The comprehension
...
returns another sequence formed from the values produced
}
by the yield part. There can be several generators and
Special syntax exists for function applications appearing on lters in a comprehension.
the left-hand side of an assignment; these are interpreted as For comprehensions are mapped to combinations involv-
update method. For instance, the assign-
applications of an ing the higher-order methodsmap, flatMap, and filter. For
ment a(i) = a(i) + 1 is interpreted as sqrts method above would
instance, the formulation of the
be mapped to the previous implementation of sqrts in Sec-
a.update(i, a.apply(i) + 1) . tion 4.4.
The power of for comprehensions comes from the fact
The interpretation of array accesses as function applications
that they are not tied to a particular data type. They
might seem costly. However, inlining transformations in the
can be constructed over any carrier type that denes ap-
Scala compiler transform code such as the one above to prim-
propriate map, flatMap, and filter methods. This includes
itive array accesses in the host system. 3
all sequence types , optional values, database interfaces, as
The above denition of the Array class also lists methods
well as several other types. Scala users might apply for-
exists and forall. Hence, it would not have been necessary
comprehensions to their own types, as long as these dene
to dene these operations by hand. Using the methods in
the required methods.
class Array, the hasZeroRow function can also be written as
For loops are similar to comprehensions in Scala.
follows.
They are mapped to combinations involving methods

def hasZeroRow(matrix: Array[Array[int]]) = foreach and filter. For instance, the for loop

matrix exists (row => row forall (0 ==)); for (val arg <- args) ... in Listing 1 is mapped to

Note the close correspondence of this code to a verbal spec- args foreach (arg => ...)
ication of the task: test whether in the matrix there exists
a row such that in the row all elements are zeroes. Note
also that we left out the type of the row parameter in the 5 Abstraction
anonymous function. This type can be inferred by the Scala
compiler from the type of matrix.exists. An important issue in component systems is how to abstract
from required components. There are two principal forms
4.4 Sequences of abstraction in programming languages: parameterization
and abstract members. The rst form is typically functional
Higher-order methods are very common when processing se- whereas the second form is typically object-oriented. Tra-
quences. Scala's library denes several dierent kinds of se- ditionally, Java supported functional abstraction for values
quences including lists, streams, and iterators. All sequence and object-oriented abstraction for operations. The new
types inherit from trait scala.Seq; and they all dene a set Java 1.5 with generics supports functional abstraction also
of methods which streamlines common processing tasks. For for types.
instance, the map method applies a given function uniformly Scala supports both styles of abstraction uniformly for
to all sequence elements, yielding a sequence of the function types as well as values. Both types and values can be pa-
results. Another example is the filter method, which ap- rameters, and both can be abstract members. The rest of
plies a given predicate function to all sequence elements and this section presents both styles and reviews at the same
returns a sequence of those elements for which the predicate time a large part of Scala's type system.
is true.
3 Arrays do not yet dene all of sequence methods, because some
The application of these two functions is illustrated in
of them require run-time types, which are not yet implemented
the following function, sqrts, which takes a list xs of double
precision numbers, and returns a list consisting of the square
roots of all non-negative elements of xs.

6
5.1 Functional Abstraction Variance. The combination of subtyping and generics in
a language raises the question how they interact. If C is
The following class denes cells of values that can be read
a type constructor and S is a subtype of T, does one also
and written.
have that C[S] is a subtype of C[T ]? Type constructors with

class GenCell[T](init: T) { this property are called covariant. The type constructor

private var value: T = init; GenCell should clearly not be covariant; otherwise one could
def get: T = value; construct the following program which leads to a type error
def set(x: T): unit = { value = x } at run time.
}
val x: GenCell[String] = new GenCell[String];
The class abstracts over the value type of the cell with the val y: GenCell[Any] = x; // illegal!
type parameter T. We also say, class GenCell is generic. y.set(1);
Like classes, methods can also have type parameters. val z: String = y.get
The following method swaps the contents of two cells, which
It is the presence of a mutable variable inGenCell which
must both have the same value type.
makes covariance unsound. GenCell[String] is
Indeed, a

def swap[T](x: GenCell[T], y: GenCell[T]): unit = { not a special instance of a GenCell[Any] since there are
val t = x.get; x.set(y.get); y.set(t) things one can do with a GenCell[Any] that one cannot do
} with a GenCell[String]; set it to an integer value, for in-
stance.
The following program creates two cells of integers and then On the other hand, for immutable data structures, co-
swaps their contents. variance of constructors is sound and very natural. For in-
stance, an immutable list of integers can be naturally seen
val x: GenCell[int] = new GenCell[int](1);
as a special case of a list of Any. There are also cases where
val y: GenCell[int] = new GenCell[int](2);
contravariance of parameters is desirable. An example are
swap[int](x, y)
output channels Chan[T], with a write operation that takes
Actual type arguments are written in square brackets; they a parameter of the type parameter T. Here one would like
replace the formal parameters of a class constructor or to have Chan[S ] <: Chan[T ] whenever T <: S .

method. Scala denes a sophisticated type inference sys- Scala allows to declare the variance of the type parame-

tem which permits to omit actual type arguments in both ters of a class using plus or minus signs. A  + in front of a

cases. Type arguments of a method or constructor are in- parameter name indicates that the constructor is covariant

ferred from the expected result type and the argument types in the parameter, a  − indicates that it is contravariant,

by local type inference [40, 38]. Hence, one can equivalently and a missing prex indicates that it is non-variant.

write the example above without any type arguments: For instance, the following trait GenList denes a simple
covariant list with methods isEmpty, head, and tail.
val x = new GenCell(1);
val y = new GenCell(2); trait GenList[+T] {
swap(x, y) def isEmpty: boolean;
def head: T;
def tail: GenList[T]
Parameter bounds. Consider a method updateMax which }
sets a cell to the maximum of the cell's current value and a
Scala's type system ensures that variance annotations are
given parameter value. We would like to dene updateMax so
sound by keeping track of the positions where a type pa-
that it works for all cell value types which admit a compar-
rameter is used. These positions are classied as covariant
ison function  < dened in trait Ordered. For the moment
for the types of immutable elds and method results, and
assume this trait is dened as follows (a more rened version
contravariant for method argument types and upper type
of this trait is in the standard Scala library).
parameter bounds. Type arguments to a non-variant type

trait Ordered[T] { parameter are always in non-variant position. The position

def < (x: T): boolean; ips between contra- and co-variant inside a type argument

} that corresponds to a contravariant parameter. The type


system enforces that covariant (respectively, contravariant)
The updateMax method can be dened in a generic way by type parameters are only used in covariant (contravariant)
using bounded polymorphism: positions.
Here are two implementations of the GenList class:
def updateMax[T <: Ordered[T]](c: GenCell[T], x: T) =
if (c.get < x) c.set(x) object Empty extends GenList[All] {
def isEmpty: boolean = true;
Here, the type parameter clause [T <: Ordered[T]] intro- def head: All = throw new Error("Empty.head");
duces a bounded type parameter T. It restricts the type def tail: List[All] = throw new Error("Empty.tail");
arguments for T to those types T that are a subtype of }
Ordered[T ]. Therefore, the < method of class Ordered can class Cons[+T](x: T, xs: GenList[T])
be applied to arguments of type T. The example shows that extends GenList[T] {
the bounded type parameter may itself appear as part of the def isEmpty: boolean = false;
bound, i.e. Scala supports F-bounded polymorphism [10]. def head: T = x;
def tail: GenList[T] = xs

7
} pression denotes instances of type GenList where the type
argument is an arbitrary subtype of T.
Note that the Empty object represents the empty list for all Covariant wildcards can be used in every type expression;
element types. Covariance makes this possible, since Empty's however, members where the type variable does not appear
type, GenList[All] is a subtype of GenList[T ], for any el- in covariant position are then forgotten in the type. This
ement type T. is necessary for maintaining type soundness. For instance,
the type GenCell<? extends Number> would have just the
Binary methods and lower bounds. So far, we have single member get of type Number, whereas the set method,
associated covariance with immutable data structures. In in which GenCell’s type parameter occurs contravariantly,
fact, this is not quite correct, because of binary methods. For would be forgotten.
instance, consider adding a prepend method to the GenList In an earlier version of Scala we also experimented with
trait. The most natural denition of this method takes an usage-site variance annotations similar to wildcards. At
argument of the list element type: rst-sight, this scheme is attractive because of its exibility.
A single class might have covariant as well as non-variant
trait GenList[+T] { ... fragments; the user chooses between the two by placing
def prepend(x: T): GenList[T] = // illegal! or omitting wildcards. However, this increased exibility
new Cons(x, this) comes at price, since it is now the user of a class instead of
}
its designer who has to make sure that variance annotations
are used consistently. We found that in practice it was quite
However, this is not type-correct, since now the type param-
dicult to achieve consistency of usage-site type annota-
eter T appears in contravariant position inside trait GenList.
tions, so that type errors were not uncommon. By contrast,
Therefore, it may not be marked as covariant. This is a pity
declaration-site annotations proved to be a great help in
since conceptually immutable lists should be covariant in
getting the design of a class right; for instance they provide
their element type. The problem can be solved by general-
excellent guidance on which methods should be generalized
izing prepend using a lower bound:
with lower bounds. Furthermore, Scala's mixin composi-
trait GenList[+T] { ... tion (see Section 6) makes it relatively easy to factor classes
def prepend[S >: T](x: S): GenList[S] = // OK into covariant and non-variant fragments explicitly; in Java's
new Cons(x, this) single inheritance scheme with interfaces this would be ad-
} mittedly much more cumbersome. For these reasons, later
versions of Scala switched from usage-site to declaration-site
prepend is now a polymorphic method which takes an ar- variance annotations.
gument of some supertype S of the list element type, T.
It returns a list with elements of that supertype. The
new method denition is legal for covariant lists since
5.2 Abstract Members
lower bounds are classied as covariant positions; hence the Object-oriented abstraction can be used in Scala as an al-
type parameter T now appears only covariantly inside trait ternative to functional abstraction. For instance, here is a
GenList. version of the cell type using object-oriented abstraction.
It is possible to combine upper and lower bounds in the
declaration of a type parameter. An example is the following abstract class AbsCell {
method less of class GenList which compares the receiver type T;
list and the argument list. val init: T;
private var value: T = init;
trait GenList[+T] { ... def get: T = value;
def less[S >: T <: Ordered[S]](that: List[S]) = def set(x: T): unit = { value = x }
!that.isEmpty && }
(this.isEmpty ||
this.head < that.head || The AbsCell class denes neither type nor value parameters.
this.head == that.head && Instead it has an abstract type member T and an abstract
this.tail less that.tail) value member init. Instances of that class can be created
} by implementing these abstract members with concrete def-
initions. For instance:
The method's type parameter S is bounded from below by
the list element type T and is also bounded from above by val cell = new AbsCell { type T = int; val init = 1 }
Ordered[S]. The lower bound is necessary to maintain co- cell.set(cell.get * 2)
variance of GenList. The upper bound is needed to ensure
The type of cell is AbsCell { type T = int }. Here,
that the list elements can be compared with the < operation.
the class type AbsCell is augmented by the renement
{ type T = int }. This makes the type alias cell.T = int
Comparison with wildcards. Java 1.5 also has a way to
known to code accessing the cell value. Therefore, type-
annotate variances which is based on wildcards [43]. The
specic operations such as the one below are legal.
scheme is essentially a syntactic variant of Igarashi and Vi-
roli's variant parametric types [26]. Unlike in Scala, in Java cell.set(cell.get * 2)
1.5 annotations apply to type expressions instead of type
declarations. As an example, covariant generic lists could be
expressed by writing every occurrence of the GenList type Path-dependent types. It is also possible to access
to match the form GenList<? extends T >. Such a type ex- AbsCell without knowing the binding of its type member.

8
For instance, the following method resets a given cell to its Without the singleton typethis.type, this would not have
initial value, independently of its value type. d.incr would be of type C, which does
been possible, since
not have a decr member. In that sense, this.type is similar
def reset(c: AbsCell): unit = c.set(c.init); to (covariant uses of ) Kim Bruce's mytype [9].
Why does this work? In the example above, the expres-
sion c.init has type c.T, and the method c.set has type Family polymorphism and self types. Scala's abstract
c.T => unit. Since the formal parameter type and the ar- type concept is particularly well suited for modeling fami-
gument type coincide, the method call is type-correct. lies of types which vary together covariantly. This concept
c.T is an instance of a path-dependent type. In gen- has been called family polymorphism. As an example, con-
eral, such a type has the form x1 . . . . .xn .t, where n > 0, sider the publish/subscribe design pattern. There are two
x1 , . . . , xn denote immutable values and t is a type member classes of participants  subjects and observers. Subjects de-
of xn . Path-dependent types are a novel concept of Scala; ne a method subscribe by which observers register. They
their theoretical foundation is provided by the ν Obj calculus also dene a publish method which noties all registered
[35]. observers. Notication is done by calling a method notify
Path-dependent types rely on the immutability of the which is dened by all observers. Typically, publish is called
prex path. Here is an example where this immutability is when the state of a subject changes. There can be several
violated. observers associated with a subject, and an observer might
observe several subjects. The subscribe method takes the
var flip = false; identity of the registering observer as parameter, whereas an
def f(): AbsCell = { observer's notify method takes the subject that did the no-
flip = !flip; tication as parameter. Hence, subjects and observers refer
if (flip) new AbsCell { type T = int; val init = 1 } to each other in their method signatures.
else new AbsCell { type T = String; val init = "" } All elements of this design pattern are captured in the
} following system.
f().set(f().get) // illegal!
trait SubjectObserver {
In this example subsequent calls to f() return cells where type S <: Subject;
the value type is alternatingly int and String. The last type O <: Observer;
statement in the code above is erroneous since it tries to abstract class Subject: S {
set an int cell to a String value. The type system does private var observers: List[O] = List();
not admit this statement, because the computed type of def subscribe(obs: O) =
f().get would be f().T. This type is not well-formed, since observers = obs :: observers;
the method callf() is not a path. def publish =
for (val obs <- observers) obs.notify(this);
Type selection and singleton types. In Java, where }
classes can also be nested, the type of a nested class is trait Observer {
denoted by prexing it with the name of the outer class. def notify(sub: S): unit;
In Scala, this type is also expressible, in the form of }
Outer # Inner, where Outer is the name of the outer class }
in which class Inner is dened. The  # operator denotes
The top-level trait SubjectObserver has two member
a type selection. Note that this is conceptually dierent
classes: one for subjects, the other for observers. The
from a path dependent type p.Inner, where the path p de-
Subject class denes methods subscribe and publish. It
notes a value, not a type. Consequently, the type expression
maintains a list of all registered observers in the private
Outer # t is not well-formed if t is an abstract type dened
variableobservers. The Observer trait only declares an
in Outer.
abstract method notify.
In fact, path dependent types in Scala can be expanded
Note that the Subject and Observer classes do not di-
to type selections. The path dependent type p.t is taken as a
rectly refer to each other, since such hard references would
shorthand for p.type # t. Here, p.type is a singleton type, prevent covariant extensions of these classes in client code.
which represents just the object denoted by p. Singleton
Instead,SubjectObserver denes two abstract types S and
types by themselves are also useful for supporting chaining
O which are bounded by the respective class types Subject
of method calls. For instance, consider a class C with a
and Observer. The subject and observer classes use these
method incr which increments a protected integer eld, and
abstract types to refer to each other.
a subclass D of C which adds a decr method to decrement
Note also that class Subject carries an explicit type an-
that eld.
notation:

class C {
class Subject: S { ...
protected var x = 0;
def incr: this.type = { x = x + 1; this } Here, S is called a self-type Subject. When a self-
of class
} type is given, it is taken as the type of this inside the class
class D extends C { (without a self-type annotation the type of this is taken as
def decr: this.type = { x = x - 1; this } usual to be the type of the class itself ). In class Subject, the
} self-type is necessary to render the call obs.notify(this)
type-correct.
Then we can chain calls to the incr and decr method, as in
Self-types can be arbitrary; they need not have a rela-
val d = new D; d.incr.decr; tion with the class being dened. Type soundness is still

9
guaranteed, because of two requirements: (1) the self-type more general than import clauses in Java. They can be used
of a class must be a subtype of the self-types of all its base anywhere, and can import members from of any object, not
classes, (2) when instantiating a class in a new expression, just from a package.
it is checked that the self type of the class is a supertype of
the type of the object being created. 5.3 Modeling Generics with Abstract Types
Self-types were rst introduced in the ν Obj calculus.
They are relatively infrequently used in Scala programs, but The presence of two type abstraction facilities in one lan-
they are nevertheless essential in situations where family guage raises the question of language complexity  could we
polymorphism is combined with explicit references to this. have done with just one formalism? In this section we show
The mechanism dened in the publish/subscribe pattern that functional type abstraction ( aka generics) can indeed be
can be used by inheriting from SubjectObserver, dening modeled by object-oriented type abstraction ( aka abstract
application specic Subject and Observer classes. An ex- types). The idea of the encoding is as follows.
ample is the SensorReader object below that takes sensors Assume you have a parameterized class C with a type
as subjects and displays as observers. parameter t (the encoding generalizes straightforwardly to
multiple type parameters). The encoding has four parts,
object SensorReader extends SubjectObserver { which aect the class denition itself, instance creations of
type S = Sensor; the class, base class constructor calls, and type instances of
type O = Display; the class.
abstract class Sensor extends Subject {
val label: String; 1. The class denition of C is re-written as follows.
var value: double = 0.0;
class C {
def changeValue(v: double) = {
type t;
value = v;
/* rest of class */
publish;
}
}
} That is, parameters of the original class are modeled
abstract class Display extends Observer { as abstract members in the encoded class. If the type
def println(s: String) = ... parameter t has lower and/or upper bounds, these carry
def notify(sub: Sensor) = over to the abstract type denition in the encoding.
println(sub.label + " has value " + sub.value); The variance of the type parameter does not carry over;
} variances inuence instead the formation of types (see
} Point 4 below).

In this object, type S is bound to Sensor whereas type O is 2. Every instance creation new C [T ] with type argument
bound to Display. Hence, the two formerly abstract types T is rewritten to:
are now dened by overriding denitions. This tying the
knot is always necessary when creating a concrete class in- new C { type t = T }
stance. On the other hand, it would also have been possible
to dene an abstract SensorReader class which could be re- 3. If C [T ] appears as a superclass constructor, the inher-

ned further by client code. In this case, the two abstract iting class is augmented with the denition

types would have been overridden again by abstract type type t = T


denitions.
4. Every type C[T ] is rewritten to one of the following
class AbsSensorReader extends SubjectObserver {
types which each augment class C with a renement.
type S <: Sensor;
type O <: Display; C { type t = T } if t is declared non-variant,
... C { type t <: T } if t is declared co-variant,
} C { type t >: T } if t is declared contra-variant.

The following program illustrates how the SensorReader ob-


This encoding works except for possible name-conicts.
ject is used.
Since the parameter name becomes a class member in the
object Test { encoding, it might clash with other members, including in-
import SensorReader._; herited members generated from parameter names in base
val s1 = new Sensor { val label = "sensor1" } classes. These name conicts can be avoided by renaming,
val s2 = new Sensor { val label = "sensor2" } for instance by tagging every name with a unique number.
def main(args: Array[String]) = { The presence of an encoding from one style of abstraction
val d1 = new Display; val d2 = new Display; to another is nice, since it reduces the conceptual complex-
s1.subscribe(d1); s1.subscribe(d2); ity of a language. In the case of Scala, generics become
s2.subscribe(d1); simply syntactic sugar which can be eliminated by an en-
s1.changeValue(2); s2.changeValue(3); coding into abstract types. However, one could ask whether
} the syntactic sugar is warranted, or whether one could have
} done with just abstract types, arriving at a syntactically
smaller language. The arguments for including generics in
Note the presence of an import clause, which makes the
Scala are two-fold. First, the encoding into abstract types
members of object SensorReader available without prex
is not that straightforward to do by hand. Besides the loss
to the code in object Test. Import clauses in Scala are
in conciseness, there is also the problem of accidental name

10
conicts between abstract type names that emulate type pa- single inheritance; i.e., programmers can specialize classes
rameters. Second, generics and abstract types usually serve Buffer with additional meth-
by subclassing. To enrich class
distinct roles in Scala programs. Generics are typically used ods forall and exists, we could, for instance, create a sub-
when one needs just type instantiation, whereas abstract class of IterableBuffer dening the new functionality:
types are typically used when one needs to refer to the ab-
stract type from client code. The latter arises in particular
class IterableBuffer[T] extends Buffer[T] {
in two situations: One might want to hide the exact deni-
def forall(p: T => Boolean): Boolean = {
tion of a type member from client code, to obtain a kind of
val it = elements; var res = true;
encapsulation known from SML-style module systems. Or
while (res && it.hasNext) { res = p(it.next) }
res
one might want to override the type covariantly in subclasses
}
to obtain family polymorphism.
def exists(p: T => Boolean): Boolean = {
Could one also go the other way, encoding abstract types
val it = elements; var res = false;
with generics? It turns out that this is much harder, and
while (!res && it.hasNext) { res = p(it.next) }
that it requires at least a global rewriting of the program.
res
This was shown by studies in the domain of module sys-
}
tems where both kinds of abstraction are also available
}
[27]. Furthermore in a system with bounded polymorphism,
this rewriting might entail a quadratic expansion of type
bounds [8]. In fact, these diculties are not surprising if one Mixin-class composition The problem with the code

considers the type-theoretic foundations of both systems. above is its limited potential for reuse. Imagine there is an

Generics (without F-bounds) are expressible in System F<: independent extension of class Buffer which models stacks:
[11] whereas abstract types require systems based on depen-
class Stack[T] extends Buffer[T] {
dent types. The latter are generally more expressive than
def push(elem: T): Unit = add(elem);
the former; for instance ν Obj with its path-dependent types def pop: T = { val y = xs.head; xs = xs.tail; y }
can encode F<: . }

6 Composition With single inheritance, it is impossible to reuse the existing


denitions of the forall and the exists methods together
mixin-class com-
6.1 Class Reuse with stacks.
position
Therefore, Scala provides a
mechanism which allows programmers to reuse the
The reuse of existing software components for the construc- delta of a class denition, i.e., all new denitions that are not
tion of new systems has many advantages: one can expect inherited, in the denition of a new class. This mechanism
lower development costs due to a reduced development time, makes it possible to combine IterableBuffer with Stack:
decreased maintenance requirements, as well as increased re-
class IterableStack[T] extends Stack[T]
liability and consistency.
with IterableBuffer[T];
Therefore, object-oriented programming languages are
equipped with mechanisms that facilitate the reuse of ex- This program denes a class IterableStack[T] which inher-
isting software artifacts, like classes. This section presents its all denitions from Stack[T] and additionally includes
and motivates Scala's class reuse mechanisms based on the the new denitions of IterableBuffer[T]. Mixing a class C
following example program. This program denes a generic into another class D is legal only as long as D's superclass
class Buffer[T] for assembling sequences of elements: is a subclass of C 's superclass. Thus, the mixin compo-
sition in the program above is well-formed, since the su-
class Buffer[T] {
IterableStack is a subclass of the superclass of
perclass of
var xs: List[T] = Nil;
IterableBuffer.
def add(elem: T): Unit = xs = elem :: xs;
Scala enforces this requirement for type-safety reasons.
def elements: Iterator[T] = new BufferIterator;
Since only the delta of a class is copied into another class
class BufferIterator extends Iterator[T] {
by a mixin-class composition, it could otherwise happen that
var ys = xs;
def hasNext: Boolean = !ys.isEmpty; some mixed-in members refer to inherited members which

def next: T = { are not present in the new context, yielding a method not

val res = ys.head; ys = ys.tail; res found exception.

}
} Ambiguities In Scala, every class inherits exactly from
} one superclass and acquires class members from multiple
other classes via mixin-based class composition. Imagine for
The implementation of class Buffer relies on the following instance the following subclass of Buffer which introduces
iterator abstraction:
a method sameElements together with an internally used
trait Iterator[T] { forall method.
def hasNext: Boolean; class ComparableBuffer[T] extends Buffer[T] {
def next: T; def forall(p: T => Boolean): Boolean = {
} val it = elements; var res = true;
while (res && it.hasNext) { res = p(it.next) }
Inheritance Like most mainstream object-oriented lan- res
guages, Scala's primary class reuse mechanism is based on }

11
def sameElements(b: IterableBuffer[T]): Boolean = val it = elements; var res = true;
forall(elem => b.exists(elem.equals)); while (res && it.hasNext) { res = p(it.next) }
} res
}
MyStack oering functional-
We could derive a stack class def exists(p: T => Boolean): Boolean = {
ity provided by both IterableBuffer and ComparableBuffer val it = elements; var res = false;
by using the two classes as mixins: while (!res && it.hasNext) { res = p(it.next) }
res
class MyStack[T] extends Stack[T]
}
with IterableBuffer[T]
}
with ComparableBuffer[T]; // error!
Trait Iterable denes methods forall and exists as be-
In Scala, methods dened in mixins either represent new
methods or they override the respective methods in the ac-
fore, but defers the denition of method elements  it
tual superclass. As the previous example shows, it may
is abstract in the terminology of Java. As opposed to
class IterableBuffer, this trait can be mixed into all
happen that two mixins dene the same method. For class
classes. If Iterable is mixed into a class without a concrete
MyStack it is unclear which forall method to use. This
elements method, then the resulting class will have a de-
ambiguity constitutes a compile-time error which has to be
ferred elements method, otherwise, the concrete method will
resolved by the programmer explicitly. A possible solution
implement the deferred method mentioned in trait Iterable.
is to introduce a new forall method which forwards the
Thus, concrete methods always override abstract ones in
call to the desired implementation. The following program
mixin-class compositions. This principle is exploited in the
makes use of the super[C] primitive, which allows one to
following alternative denition of class IterableBuffer:
refer to concrete denitions in the mixin class C:
class IterableBuffer[T] extends Buffer[T]
class MyStack[T] extends Stack[T]
with Iterable[T];
with IterableBuffer[T]
with ComparableBuffer[T] {
override def forall(p: T => Boolean) =
super[IterableBuffer].forall(p);
6.3 Layering Classes and Traits
} Scala's mixin-class composition mechanism makes it easy to
compose complex classes with extensive functionality from
smaller and simpler ones that model only particular aspects.
6.2 Traits The previous section showed how traits can be used to create
generic abstractions that can be used to add new methods
Besides ambiguities, another serious problem of multiple
or to implement deferred methods of existing classes. Traits
inheritance is the diamond inheritance dilemma which ap-
mixed into a class can also override existing methods, as the
pears if a class inherits from two other classes that share su-
following code fragment shows:
perclasses. Without further restrictions, these superclasses
would get inherited twice in this scenario. This would lead to trait Displayable[T] {
a duplication of the state encapsulated by these superclasses def elements: Iterator[T];
and therefore would result in serious consistency issues. override def toString(): String = {
To avoid this, Scala allows a class to be mixed into an- val res = new StringBuffer;
other class only if it has not been used before in the other for (val elem <- elements) res.append(" " + elem);
class as either superclass or mixin. Unfortunately, this rule res.toString()
is very restrictive, ruling out many cases where inheriting }
twice from the same class would not constitute a problem }
 this is the case in particular for classes that do not en- class DisplayableBuffer[T] extends IterableBuffer[T]
capsulate state (interfaces in Java fall into that category). with Displayable[T];
For this reason, Scala introduces the notion of traits. Traits
are abstract classes that do not encapsulate state, neither Class DisplayableBuffer[T] now provides the toString()
in form of variable denitions nor by providing a construc- method dened in trait Displayable[T].
tor with parameters. Opposed to interfaces in Java though, The presented technique for overriding methods only
they may implement concrete methods. works if the method in the superclass or in the mixed in
Since traits do not encapsulate state, inheriting twice traits is concrete. But often, one would like to dene generic
from a trait is legal in Scala. It is therefore possible to have traits that enhance an existing method by overriding with-
the same trait multiple times in the superclass hierarchy of out that method being concrete in the superclass. As an
a class. example, consider providing a building block for making it-
Reuse of class IterableBuffer is also restricted by erators synchronized such that they can be used in a con-
the requirement that it can only be mixed into classes current setting. A naive denition would be:
that Buffer.
subclass But the functionality provided
// erroneous trait definition
by IterableBuffer only depends on the existence of an
trait SynchronizedIterator[T] extends Iterator[T] {
elements method. Scala makes it possible to express this
override def next: T = synchronized { super.next }
in the following form:
override def hasNext: Boolean =
trait Iterable[T] { synchronized { super.hasNext }
def elements: Iterator[T]; }
def forall(p: T => Boolean): Boolean = {

12
This denition is illegal, because supertrait Iterator does the provided services, deferred members can be seen as the
not provide concrete implementations for both methods next required services. The composition of components is based
and hasNext. Thus, the super reference is not allowed. on mixins, which allow programmers to create bigger com-
Scala still allows programmers to dene such an abstrac- ponents from smaller ones.
tion. However, it requires that an abstract modier is used The mixin-class composition mechanism of Scala iden-
for all those methods which override abstract methods in ties services with the same name; for instance, a de-
the static superclass, yet which are supposed to override ferred method m can be implemented by a class C den-
concrete methods in a mixin composition. ing a concrete method m simply by mixing-in C. Thus,
the component composition mechanism associates automat-
trait SynchronizedIterator[T] extends Iterator[T] { ically required with provided services. Together with the
abstract override def next: T = rule that concrete class members always override deferred
synchronized { super.next } ones, this principle yields recursively pluggable components
abstract override def hasNext: Boolean = where component services do not have to be wired explic-
synchronized { super.hasNext }
itly [47].
}
This approach simplies the assembly of large compo-

Classes containing methods tagged with both abstract and nents with many recursive dependencies. It scales well even

override cannot be instantiated  they have to be declared in the presence of many required and provided services, since

abstract themselves. Furthermore, such classes can only the association of the two is automatically inferred by the

be mixed into classes that provide concrete versions for all compiler. The most important advantage over traditional

mixed in methods agged with abstract and override. black-box components is that components are extensible en-

Traits like SynchronizedIterator are extremely useful tities: they can evolve by subclassing and overriding. They

for synchronizing arbitrary iterator implementations simply can even be used to add new services to other existing com-

by a mixin composition. For instance, we could implement ponents, or to upgrade existing services of other compo-

a synchronized iterator for theBuffer class based on an nents. Overall, these features enable a smooth incremental

unsynchronized version as dened by class BufferIterator software evolution process [48].

at the beginning of Section 6.1.

class Buffer[T] { 7 Decomposition


...
def elements: Iterator[T] = 7.1 Object-Oriented Decomposition
new BufferIterator with SynchronizedIterator[T]; Often programmers have to deal with structured data. In
} an object-oriented language, structured data would typically
be implemented by a set of classes representing the various
In mainstream object-oriented languages like Java, program-
structural constructs. For inspecting structured data, a pro-
mers would typically separate concerns using object composi-
grammer can solely rely on virtual method calls of methods
tion techniques. Here, a generic synchronized iterator class
provided by such classes.
would provide synchronized methods that forward the call to
Suppose we want to implement a simple evaluator for
the corresponding methods of another unsynchronized iter-
algebraic terms consisting of numbers and a binary plus op-
ator. The advantage of this approach is its exibility, since
eration. Using an object-oriented implementation scheme,
it can be decided dynamically whether to use a synchro-
we can decompose the evaluator according to the term struc-
nized or unsynchronized iterator. On the other hand, this
ture as follows:
approach does not guarantee statically that the synchroniza-
tion scheme is adhered to at runtime, since programmers can trait Term {
possibly circumvent the programming pattern easily by ex- def eval: int;
posing the unsynchronized iterator. }
The approach based on mixin class composition turns class Num(x: int) extends Term {
iterators statically into synchronized iterators guaranteeing def eval: int = x;
that synchronization cannot be broken by programmers at }
runtime. In Scala, the programmer has the choice between class Plus(left: Term, right: Term) extends Term {
composing abstractions at runtime using object composition def eval: int = left.eval + right.eval;
or at compile-time using class composition. Whether one }
uses object or class composition depends predominantly on
the particular exibility and safety requirements. The given program models terms with trait Term which de-
nes a deferred eval method. Concrete subclasses of Term
6.4 Service-Oriented Component Model model the various term variants. Such classes have to pro-
vide concrete implementations for method eval.
Scala's class abstraction and composition mechanism can be Such an object-oriented decomposition scheme requires
seen as the basis for a service-oriented software component the anticipation of all operations traversing a given struc-
model. Software components are units of computation that ture. As a consequence, even internal methods sometimes
provide a well-dened set of services. Typically, a software have to be exposed to some degree. Adding new methods
component is not self-contained; i.e., its service implemen- is tedious and error-prone, because it requires all classes
tations rely on a set of required services provided by other to be either changed or subclassed. A related problem is
cooperating components. that implementations of operations are distributed over all
In Scala, software components correspond to classes and participating classes making it dicult to understand and
traits. The concrete members of a class or trait represent change them.

13
7.2 Pattern Matching Over Class Hierarchies guard x == y.4

The program above is a good example for cases where a


functional decomposition scheme is more appropriate. In a 8 XML Processing
functional language, a programmer typically separates the
denition of the data structure from the implementation of XML is a popular data format. Scala is designed to ease con-
the operations. While data structures are usually dened struction and maintenance of programs that deal with XML.
using algebraic datatypes, operations on such datatypes are It provides a data model for XML by means of traits and
simply functions which use pattern matching as the basic particular subclasses. Processing of XML can then be done
decomposition principle. Such an approach makes it pos- by deconstructing the data using Scala's pattern matching
sible to implement a single eval function without exposing mechanism.
articial auxiliary functions.
Scala provides a natural way for tackling the above pro- 8.1 Data Model
gramming task in a functional way by supplying the pro-
grammer with a mechanism for creating structured data Scala's data model for XML is an immutable representation
representations similar to algebraic datatypes and a decom- of an ordered unranked tree. In such a tree each node has
position mechanism based on pattern matching. a label, a sequence of children nodes, and a map from at-
Instead of adding algebraic types to the core language, tribute keys to attribute values. This is specied in the trait
Scala enhances the class abstraction mechanism to simplify scala.xml.Node which additionally contains equivalents of
the construction of structured data. Classes tagged with the the XPath operators child and descendant-or-self, which are
case modier automatically dene a constructor with the written \ and \\. Concrete subclasses exist for elements,
same arguments as the primary constructor. Furthermore, text nodes, comments, processing instructions, and entity
Scala introduces pattern matching expressions in which it references.
is possible to use such constructors of case classes as pat- XML syntax can be used directly in a Scala program,
terns. Using case classes, the algebraic term example can be e.g., in value denitions.
implemented as follows:
val labPhoneBook =
trait Term; <phonebook>
case class Num(x: int) extends Term; <descr>Phone numbers of<b>XML</b> hackers.</descr>
case class Plus(left: Term, right: Term) extends Term; <entry>
<name>Burak</name>
Given these denitions, it is now possible to create the <phone where="work"> +41 21 693 68 67 </phone>
algebraic term 1 + 2 + 3 without using the new primi- <phone where="mobile"> +41 78 601 54 36 </phone>
tive, simply by calling the constructors associated with case </entry>
classes: Plus(Plus(Num(1), Num(2)), Num(3)). Scala's </phonebook>;
pattern matching expressions provide a means of decompo-
sition that uses these constructors as patterns. Here is the The value labPhoneBook is an XML tree; one of its nodes has
implementation of the eval function using pattern match- the label phone, a child sequence consisting of a text node
ing: labeled by +41 2.., and a map from the attribute key where
to the value "work". Within XML syntax it is possible to es-
object Interpreter { cape to Scala using the brackets { and } (similar to the con-
def eval(term: Term): int = term match { vention used in XQuery). For example, a date node with a
case Num(x) => x child text node consisting of the current date can be dened
case Plus(left, right) => eval(left) + eval(right); by <date>{ df.format(new java.util.Date()) }</date>.
}
}
8.2 Schema Validation
The matching expression x match { case pat1 => e1 Types of XML documents are typically specied by so called
case pat2 => e2 ...} matches value x against the patterns schemas. Popular schema formalisms are DTDs (Docu-
pat1 , pat2 , etc. in the given order. The program above uses ment Type Denitions) [7], XML Schema [18], and RELAX
patterns of the form Constr(x1 , ..., xn ) where Constr refers NG [33]. At this moment a simple support for DTDs is
to a case class constructor and xi denotes a variable. An ob- available through the dtd2scala tool. It converts a DTD to
ject matches such a pattern if it is an instance of the corre- a set of class denitions which can only be instantiated with
sponding case class. The matching process also instantiates XML data that is valid with respect to the DTD. Existing
the variables of the rst matching pattern and executes the XML documents can then be validated against the DTD by
corresponding right-hand-side. using a special load method which tries to instantiate the
Such a functional decomposition scheme has the ad- corresponding classes (using pattern matching). In the fu-
vantage that new functions can be added easily to ture, support for the richer set of types of XML Schema
the system. On the other hand, integrating a new is planned, including static type checking through regular
case class might require changes in all pattern match- types.
ing expressions. Some applications might also prot
4
Patterns in Scala are linear in the sense that a variable may ap-
from the possibility of dening nested patterns, or pat-
pear only once within a pattern.
terns with guards. For instance, the nested pattern
case Plus(x, y) if x == y => ... matches only terms of
the form t + t. The equivalence of the two variables x and
y in the previous pattern is established with the help of the

14
8.3 Regular Sequence Pattern Matching 9 Autonomous Components
XML nodes can be decomposed using pattern matching.
The Scala language as such does not provide any primi-
Scala allows to use XML syntax here too, albeit only to
tives for concurrent programming. Instead the core lan-
match elements. The following example shows how to add
guage has been designed to make it easy to build libraries
an entry to a phonebook element. to provide dierent concurrency models built on top of the
thread model of the underlying host language. In this sec-
import scala.xml.Node ;
tion we will exemplify the power of Scala by implementing
def add(phonebook: Node, newEntry: Node): Node =
a small library for fault-tolerant active objects with a avor
phonebook match {
of Erlang-like actors [1].
case <phonebook>{ cs @ _* }</phonebook> =>
<phonebook>{ cs }{ newEntry }</phonebook> Imagine for example that you have written a server class

} MyServer that is invoked by calling the method startServer.


val newPhoneBook = Scala makes it possible to make this server concurrent just

add(scala.xml.nobinding.XML.load("savedPhoneBook"), by mixing it into the thread class.


<entry>
class MyConcurrentServer extends Thread with MyServer {
<name>Sebastian</name>
override def run() = startServer;
<phone where="work">+41 21 693 68 67</phone>
}
</entry>);
We can generalize the code above to a class, lets call it
The add function performs a match on the phonebook ele-
Process, which can take arbitrary code and execute it in a
ment, binding its child sequence to the variable cs (the reg-
separate thread.
ular sequence pattern _* matches an arbitrary sequence).
Then it constructs a new phonebook element with child se- class Process(def body: unit) extends Thread {
quence cs followed by the node newEntry. override def run() = body;
Regular sequence patterns extend conventional algebraic }
patterns discussed in Section 7 with the regular expression
constructs * (zero to arbitrary repetition of a sequence), ? To make it even easier to spawn new processes we can im-
(zero or one occurrence of a sequence), and | (to describe plement a spawn function in an object.
an alternative of sequences). They can be applied to any
object Process {
sequence, i.e. any instance of Seq[A]. The following example
def spawn(def body: unit): Process = {
illustrates their use.
val p = new Process(body); p.start(); p
def findRest(z: Seq[Char]): Seq[Char] = z match { }
case Seq(_*, ’G’, ’o’, ’o’*, ’g’, ’l’, ’e’, }
rest@(_*)) => rest
Now we can start a process, but how do we stop it? Well
}
a process stops when it has no more code to execute, i.e.,
This pattern is used to search for the sequence of letters when the code in body reaches its end. Sometimes we would
"Gogle" or "Google", or . . . . If the input z matches, then like to kill the process prematurely, we can do this by adding
the function returns what remains after the occurrence, oth- an exit method to the Process class.
erwise it generates a runtime error. Ambiguities that emerge
class Process(def body: unit) extends Thread {
(e.g., for several occurrences of 'Go*gle-words' in z) are re-
private var exitReason: AnyRef = null;
solved using the (left) shortest match policy which chooses
override def run() = {
the shortest match for each possibility (such as a *), coming
try { body }
from the left. In the example this coincides with matching
catch {
the rst occurrence of "Goo*gle" in the input z.
case e: InterruptedException =>
exitReason match {
8.4 XML Queries through For Comprehension case null => Console.println(
"Process exited abnormally " + e);
A pattern match determines at most one match of a pattern.
case _ => Console.println(
When querying XML one is often interested in locating all "Process exited with reason: " +
matches to a query. Scala's exible comprehension mecha-
exitReason);
nism can be used to query XML in a concise and elegant
}
style that closely resembles XQuery. In the following exam-
}
ple, we select all entry elements from labAddressbook and
}
from labPhoneBook into the variables a and p, respectively.
def exit(reason: AnyRef): unit = {
Whenever the name contents of two such entries coincide, a
exitReason = reason; interrupt()
result element is generated which has as children the ad- }
dress and phone number, taken from the appropriate entry.
}
for (val a <- labAddressBook \\ "entry"; Just running an object in a separate thread does not give
val p <- labPhoneBook \\ "entry"; us true active objects. All method calls and eld accesses
a \ "name" == p \ "name") yield
from other threads have to be synchronized in order to be
<result>{ a.child }{ p \ "phone" }</result>
safe. Adding this synchronization by hand is error prone
and can easily lead to deadlocks or inecient code.
A better approach to thread communication is to use

15
message passing, e.g., by implementing an Erlang like actor
model. In Erlang each actor (or process in the Erlang ter- class Signal extends Message;
minology) has a mailbox to which other processes can asyn-
case class Normal() extends Signal;
chronously send messages. The process owning the mailbox
case class Exit(p: Process, m: Message)
can selectively receive messages from the mailbox. In Scala
extends Message;
we can implement mailboxes with the following signature.
class Process(def body: unit) extends Thread
class MailBox { with MailBox {
def send(msg: Any): unit; private var exitReason: AnyRef = null;
def receive[a](f: PartialFunction[Any, a]): a; private var links: List[Process] = Nil;
def receiveWithin[a](msec: long) override def run() =
(f: PartialFunction[Any, a]): a; try { body; signal(Normal()) }
} catch {
case _: InterruptedException =>
Messages are added to the mailbox by the send method. signal(exitReason);
Messages are removed using the receive method, which is case exitSignal =>
passed a message processor f as argument, which is a par- signal(exitSignal);
tial function from messages to some arbitrary result type. }
Typically, this function is implemented as a pattern match- private def signal(s: Message) =
ing expression. The receive method blocks until there is a links.foreach(
message in the mailbox for which its message processor is p: Process => p.send(Exit(this, s)));
dened. The matching message is then removed from the def !(msg: Message) = send(msg);
mailbox and the blocked thread is restarted by applying the def link(p: Process) = links = p :: links;
message processor to the message. Both sent messages and def unlink(p: Process) =
receivers are ordered in time. A receiver r is applied to a links = links.remove(p2 => p == p2);
matching message m only if there is no other (message, re- def spawnLink(def body: unit) = {
ceiver) pair which precedes (m, r) in the partial ordering on val p = new Process(body);
pairs that orders each component in time. p.link(this); p.start(); p
We can now extend our Process class by mixing in the }
MailBox class. def self = this;
def exit(reason: AnyRef): unit = {
class Process(def body: unit) extends Thread exitReason = reason; interrupt()
with MailBox { }
//... }
}
Listing 2: The Process class.
In order to build fault-tolerant systems it is imperative
that we can detect failures in a process. This can be achieved
by making it possible to link processes. When a process (A)
is linked to another process (B), A will send a signal to B
client of this library might wish to treat such lists as sets,
when A dies. This makes it possible to monitor the failure
supporting operations such as member inclusion or contain-
of processes and to implement supervision trees where a su-
ment tests. However, the provider of the class might not
pervisor process monitors worker processes and can restart
have thought of this usage scenario, and consequently might
them if they fail.
have left out these methods from the interface of GenList.
To implement this in Scala we have to add a list of links
One might argue that inheritance can allow clients to tai-
to the Process class and provide the link methods, as well
lor the supported methods of a class to their requirements;
as signal a failure to all linked processes. We can now give
however this is only true if a client has control over all cre-
the complete Process class, see Listing 2.
ation sites of the class. If the library also returns an opera-
We can use the Process class to implement a small
tion such as
counter server (see Listing 3). This server implements a
counter that can be incremented and read by sending the def fromArray(xs: Array[T]): GenList[T]
messages Increment, and GetValue respectively. The server
itself consists of only one method, the server method. The then inheritance cannot be used to turn a GenList into a
object Counter provides a functional interface to the counter SetList after it has been returned from method fromArray.
process. One can circumvent this restriction to some degree by in-
cluding factory methods [20]in libraries. However, this in-
volves fairly complicated frameworks which are dicult to
10 Component Adaptation learn and instantiate, and it fails for library components that
inherit from classes that need to be extended by clients.
Even component systems with powerful constructs for ab-
This unsatisfactory situation is commonly called the ex-
straction and composition face a problem when it comes
ternal extensibility problem. It has been argued that this
to integrating sub-systems developed by dierent groups at
problem holds back the development of software components
dierent times. The problem is that the interface of a com-
to a mature industry where components are independently
ponent developed by one group is often not quite right for
manufactured and deployed [28].
clients who wish to use that component. For instance, con-
sider a library with a class like GenList from Section 5. A

16
when a member selected from e is not a member of T. For
object Counter { instance, assume a value xs of type List[T] which is used
class Messages(); in the following two lines.
case class Increment() extends Messages;
case class GetValue(from: Process) extends Messages; val s: Set[T] = xs;
case class Stop() extends Messages; xs contains x
case class Value(value: int) extends Messages;
def start: Process = spawn(server(0)); The compiler would insert applications of the view dened
def increment(Counter: Process): unit = above into these lines as follows:
Counter ! Increment();
val s: Set[T] = view(xs);
def value(Counter: Process): int = {
view(xs) contains x
Counter ! GetValue(self);
receive { case Value(value) => value } Which views are available for insertion? Scala considers as
} candidates all views which can be accessed at the point of
def stop(Counter: Process): unit = Counter ! Stop(); insertion without a prex expression. This includes views
private def server(v: int): unit = { dened locally or in some enclosing scope, as well as views
var stop = false; inherited from base classes or imported from other objects
var value = v; by an import clause. Shadowing is not taken into account.
while (! stop) {
That is, a local view does not hide a view dened in an en-
receive {
closing scope. A view is applicable if can be applied to the ex-
case Increment() => value = value + 1;
pression and it maps to the desired type (or to any type con-
case GetValue(from) => from ! Value(value);
taining the desired member). Among all candidates, Scala
case Stop => stop = true;
picks the most specic applicable view. Here, specicity is
}
interpreted in the same way as for overloading resolution in
}
Java and Scala. It is an error if no view is applicable, or
}
among the applicable views no most specic one exists.
}
Locality is ensured by the restriction that only those
Listing 3: Example of the use of processes, a simple server. views accessible without a prex are candidates. Clients
can tailor the set of available views by selectively importing
objects dening views.
Views are used frequently in the Scala library to upgrade
Java's types to support new Scala traits. An example is
10.1 Views Scala's trait Ordered which denes a set of comparison op-
Scala introduces a new concept to solve the external exten- erations. Views from all basic types as well as class String
sibility problem: views allow one to augment a class with to this type are dened in a module scala.Predef. Since the
new members and supported traits. Views follow some of members of this module are imported implicitly into every
the intuitions of Haskell's type classes, translating them into Scala program, the views are always available. From a user's
an object-oriented approach. Unlike with type classes, the perspective, it is almost as if the Java classes are augmented
scope of a view can be controlled, and competing views can by the new traits.
coexist in dierent parts of one program.
A view is introduced by a normal Scala method denition 10.2 View Bounds
which denes an entity named view. For instance, assume
the following trait for simple generic sets: As presented so far, view methods have to be visible stati-
cally at the point of their insertion. Views become even more
trait Set[T] { useful if one can abstract over the concrete view method to
def include(x: T): Set[T]; be inserted. An example is the following generic maximum
def contains(x: T): boolean method, which returns the maximum element of a non-
} empty list.

A view from class GenList to class Set is introduced by the def maximum[T <% Ordered[T]](xs: List[T]): unit = {
following method denition. var mx = xs.head;
for (val x <- xs.tail) if (mx < x) mx = x
def view[T](xs: GenList[T]): Set[T] = new Set[T] { mx
def include(x: T): Set[T] = }
x prepend xs;
def contains(x: T): boolean = The method has a view bounded type parameter
!isEmpty && (xs.head == x || xs.tail contains x) [T <% Ordered[T]]. This type parameter can be instan-
} tiated to any type T which is a subtype of, or viewable as
Ordered[T ]. In particular, we can apply maximum to lists of
Hence, if xs is a GenList[T ], then view(xs) would return a
basic types for which standard Ordered views exist.
Set[T ].
Note that a view method application needs to be inserted
The only dierence with respect to a normal method
in the mx < x condition in method maximum. Where does this
denition is that views are inserted automatically by the
view method come from? Since it is not statically known at
Scala compiler. Say, e is an expression of type T. A view
the point of insertion, it must be passed as a parameter.
is implicitly applied to e in one of two possible situations:
In fact, for every view-bounded type parameter [t <: T ],
when the expected type of e is not (a supertype of ) T, or
an implicit value parameter (view: t => T ) is added to the

17
parameter list of a class or method. When the class con- ˆ view resolution
structor or method is called, a concrete view method which
matches the view parameter type is passed. The selection ˆ type inference

of this view method is analogous to the view selection for


ˆ type analysis
type conversions discussed in the last section.
For instance, the method call ˆ constraint checks.

maximum(List(1, -3, 42, 101))


However, most of the diculty comes from the fact that
these tasks have to be performed simultaneously because
would be completed to
each tasks needs some information provided by one or sev-
maximum(view)(List(1, -3, 42, 101)) eral others. The name analysis, the type analysis and the
overloading resolution are similar to what is done in Java
where view is the view method from int to Ordered[int] compilers. The main dierence is the presence of type
dened in scala.Predef. parametrized classes and functions which often may be omit-
ted and have to be inferred by the compiler. The type in-
10.3 Conditional Views ference is based on the colored local type inference [38].

View methods might themselves have view-bounded type


parameters. This allows the denition of conditional views. 11.3 Functions with def parameters
For instance, it makes sense to compare lists lexicographi- Functions with def parameters are rewritten to functions
cally as long as the list element type admits comparisons. where eachdef parameter of type T is replaced by a normal
This is expressed by the following view method: parameter of type Function0[T ]. For example, the deni-
tion
def view[T <% Ordered[T]](x: List[T]) =
new Ordered[List[T]] { def or(x: Boolean, def y: Boolean): Boolean =
def < (y: List[T]): boolean = if (x) true else y;
!y.isEmpty &&
(x.isEmpty || x.head < y.head || is rewritten to
x.head == y.head && x.tail < y.tail)
} def or(x: Boolean, y: Function0[Boolean]): Boolean =
if (x) true else y.apply();
The method maps elements of type List[T ] to instances of
type Ordered[List[T ]] as dened in Section 5.1, provided The example shows also that references to def parameters
the list element type T is itself viewable as Ordered[T ]. are replaced by a call to the apply method of the rewritten
parameters.
At a call site, arguments corresponding to def parame-
11 Implementation Function0. For example,
ters are replaced by instances of
the expression or(isFoo(), isBar()) is replaced by the fol-
The Scala compiler compiles Scala source code to JVM class lowing expression.
les. It supports separate compilation by storing Scala type
information in the generated class les as an attribute. or(isFoo(), new Function0[Boolean] {
The compiler consists of several phases. The rst one, def apply(): Boolean = isBar()
the parser, reads all source les and generates an abstract })
syntax tree. This tree is then passed to the successive phases
which annotate it or transform it. Finally, the tree is lin-
earized and translated to JVM bytecode. 11.4 Curried Functions
The next sections describe the dierent compiler phases
The JVM supports only functions with one parameter sec-
and the transformations applied to the Scala code. For rea-
tion. Therefore functions with multiple parameter sections
sons of space we leave out some phases and transformations.
must be eliminated. This is done by merging all sections
into one. For example, the function
11.1 Parsing
def sum(x: Int)(y: Int): Int = x + y;
The parser consists of a hand-written scanner and parser.
The parser is a standard top-down parser. The scanner is is replaced by the following one
the combination of two scanners: the Scala scanner, and the
def sum(x: Int, y: Int): Int = x + y;
XML scanner which is needed to parse the XML literals.

Partial applications of functions with multiple parameter


11.2 Code Analysis sections are replaced by anonymous functions. For example,
the denition
The code analysis phase is indisputably the most complex
of all compiler phases. This is partly due to the number of val inc: Int => Int = sum(1);
tasks it performs, including
is replaced by
ˆ name analysis
val inc: Int => Int = y => sum(1)(y) .
ˆ overloading resolution

18
11.5 Pattern Matching Expressions be illegal in the resulting top-level class. To avoid them, a
new package-private access member is added to the enclosing
Pattern matching expressions are translated into automata
class for each of its private members that is referenced by an
such that the number of tests needed to nd the rst match-
nested class and all references in nested classes to these pri-
ing pattern is minimized. Algebraic patterns as discussed
vate members are replaced by references the corresponding
in Section 7 and simple sequence patterns are translated
access members.
with the technique used by the extensible Java compiler
JaCo [49, 46]. The translation scheme corresponds closely
11.8 Mixin Expansion
to the one introduced by the Pizza compiler [36].
The more powerful regular expression patterns discussed In Scala, every class may contain code and every class may
in Section 8.3 use a dierent translation scheme which is be used as a mixin. Therefore, by using mixins, it is possible
based on the theory of regular tree grammars. to dene classes that inherit code from several other classes.
In the following example
11.6 Local Classes and Functions
trait A {
Both Scala and Java support local classes (i.e., classes de- def foo: String;
ned in the body of a function) and Scala also supports local def bar: String;
functions. These local denitions are eliminated by lifting }
them out into the next enclosing class; local classes become class B extends A {
new private classes of the enclosing class and local functions def foo: String = "foo";
become new private methods. }
The main diculty of lifting denitions is the possible class M extends A {
presence of references to variables of the enclosing function def bar: String = "bar";
in the body of the lifted denition. These references become }
invalid after the lifting because the referenced variables are class C extends B with M;
no longer in the scope of the lifted denition. This is solved
by adding to the lifted denition a new argument for every
the class C inherits the implementation of method foo from
referenced variable of the enclosing function and by replac-
class B and the implementation of method bar from class M.
The JVM supports only single class inheritance. There-
ing each reference to one of these variables by a reference to
fore, code inheritance from multiple classes has to be simu-
the corresponding new argument.
lated. This is done by copying the code that can't be inher-
This solution works well as long as all referenced vari-
ited.
ables are immutable. This is the case in Java but not in
In addition to class inheritance, the JVM supports mul-
Scala. With mutable variables, the described solution fails
tiple interface inheritance. An interface is an abstract class
because changes that occur after the lifted class is created or
that only declares members but contains no code. This
the lifted function is called will never be noticed. Further-
makes it possible to replicate any Scala type hierarchy on
more, there is no way to modify the value of the variable
the JVM.
from within the lifted denition. T
To do so, every class C is split into a trait C and a
To overcome these problems, mutable variables refer- C T
class C . The trait C contains a member declaration for
enced by local denitions are rst transformed into Cells.
For example the variable denition
every member declared in class C and, assuming that class
C extends class S and mixins M0 , ..., Mn , it extends the
T T T C
var i: Int = 0; traits S and M0 , ..., Mn . The class C extends the class
C T
S and the trait C and receives all the code from class C .
would be transformed into In addition to that, all the code from the mixins M0 , ..., Mn
C
is duplicated in class C .
val i: Cell[Int] = new Cell(0);
The code below shows how the example is transformed.
T
if it was referenced by a local denition. Note that C keeps the name of C and that the name of
C C is obtainend by appending $class to the name C .
11.7 Inner Classes trait A {
Although Java supports inner and nested classes, the JVM
def foo: String;
supports neither of them. Therefore Java compilers have
def bar: String;
}
to transform those classes into top-level classes. The Scala
abstract class A$class with A;
compiler uses techniques similar to those used by Java com-
trait B with A {
pilers.
def foo: String;
Inner classes are transformed into nested classes by
}
adding a new eld containing a reference to the enclosing
class B$class extends A$class with B {
class instance and by replacing all references to this instance
def foo: String = "foo";
by references to this new eld. All constructors are also aug-
}
mented with a new argument needed to initialize the new
trait M with A {
eld.
def bar: String;
The transformation of nested classes into top-level classes
}
involves giving them a non-conicting top-level name. The
class M$class extends A$class with M {
only diculty is the possible presence of references to pri-
def bar: String = "bar";
vate members of the enclosing class. These references would
}

19
trait C with B with M; has been formalized by Igarashi, Pierce, and Wadler in [25].
class C$class extends B$class with C { They also prove that all added type casts are safe (they
def bar: String = "bar"; never raise a ClassCastException).
}

M$class inherits the implementation


It can be seen that class
11.11 Code Generation
of method foo from class B$class, but that the implemen- In the end, the code is in a shape such that it can be easily
tation of method bar in class M$class is not inherited and linearized and converted to JVM class les. This is done in
has to be duplicated in class C$class. the last phase of the compiler. The class le generation relies
The trait CT replaces all occurrences of class C in all on FJBG: a home-grown library for fast class le generation.
types. This is possible because, by construction, it exhibits
the same inheritance graph as class C and has the same
members. Since, it contains and inherits no code, the trait
11.12 Implementation Language
C T can be mapped to a JVM interface. The class C C re- In the beginning, the whole compiler was written in Java,
places all occurrences of class C in instance creations. It is or more precisely in Pico, a Java dialect with algebraic data
mapped to a JVM class. types. Since then some phases, including the scanner, the
parser and the analyzer have been rewritten in Scala. Our
11.9 Type Mapping goal is to have a compiler entirely written in Scala. Most of
the new code is now directly written in Scala and the old
At this point, after all the previously mentioned transfor- Java code is slowly rewritten in Scala.
mations, the mapping from Scala classes to JVM classes The library is almost entirely written in Scala. The
is straightforward: every Scala class is mapped to a JVM only exceptions are some internal runtime classes and the
class with the same name. There are only two excep- value type classes along with the class Array which require
tions: Any and AnyRef which are both mapped to
classes some special handling from the compiler as described in Sec-
java.lang.Object. tion 11.9.
For performance reasons, instances of subclasses of
AnyVal are treated separately. These values are usually rep-
resented by their corresponding JVM primitive values and 12 Scala for .NET
not by instances of their class. The subclasses of AnyVal are
also replaced by their corresponding JVM primitive type The .NET platform is built around the Common Language
in function and variable declarations. For example, the Infrastructure (CLI) [15] which provides a specication for
method def size: Int is compiled to a method with the executable code and the execution environment in which it
JVM primitive type int as return type. Instances of sub- runs. The Common Language Specication (CLS) is a sub-
classes of AnyVal are created only when values of these types set of the CLI that denes rules for language interoperability.
are passed where a value of type Any or AnyVal is expected. While Scala has been developed mostly with focus on JVM,
For performance reasons, instances of class Array are also the aim is to support all CLS compliant features of .NET,
treated separately; these values are usually represented by i.e. to be a CLS consumer.
JVM native arrays. Instances of Array are created only ex-
ceptionally, for example when an array is passed where an 12.1 Class and Method Mappings
instance of Array[T ], with T <: Any, is expected because
the JVM has no native array type that is a super-type of all The dierences between the JVM and .NET start with the

other array types. java.lang.Object and


root class on both platforms, namely
System.Object. Scala abstracts over this dierence and in-
11.10 Type Erasure troduces the type scala.AnyRef as the root of the hierar-
chy for reference types (Section 3.1). In the .NET version
Although Java 1.5 introduces type parameterized classes and of Scala, AnyRef is an alias for System.Object, rather than
methods to the language, the JVM still does not support java.lang.Object.
this. Therefore, all type parameter sections are removed and The root class java.lang.Object denes several meth-
the remaining type variables are replaced by their bounds. ods, among them the familiar equals, hashCode and
Thus, types like List[Int] become List and function de- toString methods. On .NET, the root class System.Object
nitions like denes semantically equivalent methods but with dierent
names. Since AnyRef is just an alias for one of the root
def id[T](x: T): T = x; classes, it can be expected that on .NET its methods will
have names as dened in System.Object. However, this
become
would fragment the Scala language and preclude the pos-
def id(x: Any): Any = x; sibility to write Scala programs that compile and run on the
two platforms without modications.
Sometimes, a type cast needs to be added. This scala.Any, which
The root of the Scala class hierarchy is
happens when a function whose return type is a type AnyRef (Figure 3.1). It already
is the direct superclass of
variable is called or when a variable whose type is denes the equals, hashCode and toString methods. This
a type variable is used. For example, the expres- necessitates a translation of the names of the equivalent
sion id[String]("hello").length() has to be replaced by methods of System.Object (Equals → equals, ToString →
id("hello").asInstanceOf[String].length() because the toString, GetHashCode → hashCode), so that they override
function id, after transformation, has the return type Any. the corresponding method in Any. This means that, say,
This technique is also known as type erasure. It is used by the ToString method of any .NET type is accessible as
several other compilers, for example in the GJ compiler. It

20
toString from a Scala program. Furthermore, dening a get { return d; }
toString method in a Scala class will eectively override set { if (value >= -273) d = value; }
System.Object.ToString. To avoid confusion, especially }
among .NET programmers, the compiler will reject any at- }
tempt to override any of these methods under its original
The value of a property is obtained using its name (as
System.Object name.
with a eld); to set a new value, the eld assignment syntax
trait A { is used.
// ok, overrides System.Object.ToString
override def toString() = "A"; Celsius c = new Celsius(); c.degree = c.degree - 1;

Scala employs a similar technique in its treatment of vari-


// compilation error, should be ’toString’
ables, which can be extended to dening properties. The
override def ToString() = "A";
getter and setter methods of a .NET property are trans-
lated according to the Scala convention (Section 3.3) and
// ok, just another method
can be used as if they were dened in Scala.
def ToString(prefix: String): String;
} val c = new Celsius; c.degree = c.degree - 1;
Sometimes translating the name of a method is not Properties in .NET can have parameters ( indexed prop-
enough. The getClass method of java.lang.Object re- erties). In C#, they are declared using special syntax.
turns an instance of java.lang.Class, which is primarily
used for reection. System.Object denes a similar method, abstract class Map {
GetType, but it returns an instance of System.Type, which public abstract Object this[Object key] { get; set; }
serves the same purposes as java.lang.Class. While it is }
possible to implement the getClass method for .NET (using
To give access to such properties, C# employs an array
the J# runtime libraries), this method is considered to be
indexing syntax.
platform-specic and is not present in the .NET version of
Scala. One should use the GetType method and the native public void inverse(Map map, Object key) {
.NET reection facilities. Object v = map[key];
Another platform-specic feature is object cloning. On map[v] = key;
the JVM this is supported by the clone method of }
java.lang.Object. Every class that requires cloning has
to implement the java.lang.Cloneable interface and over- Such properties can be translated according to the
ride the clone method. On .NET, System.Object de- scheme used to implement arrays in Scala (Section 4.3). The
nes the MemberwiseClone method, which returns a eld- getter of an indexed property is renamed to apply, and the
by-eld (or shallow) copy of an object and cannot be over- setter to update. Then, from a Scala perspecive, the class
ridden. Object cloning is supported by implementing the Map will look like this.
System.ICloneable interface which declares a Clone method
that has to be overridden in the implementing class.
abstract class Map {
def apply(key: Any): Any;
class MyCloneable with ICloneable { def update(key: Any, value: Any): unit;
def Clone() = super.MemberwiseClone(); }
}
And can be used in a way, similar to C#.
To improve source-level compatibility, many additional
def inverse(map: Map, key: Any) = {
methods of java.lang.String have to be mapped to the
val v = map(key); map(v) = key;
appropriateSystem.String methods. At the same time, all
}
methods of System.String are accessible under their usual
names.

// java.lang.String.substring(int, int) 12.3 Value Types


val s1 = "0123".substring(1, 3)); // "12";
User-dened value types are a novel feature of the .NET
framework. They obtain their special status by extending
// System.String.Substring(int, int)
System.ValueType. Objects of value types are allocated on
val s2 = "0123".Substring(1, 3)); // "123";
the stack, as opposed to reference types which are allocated
on the heap. They are also passed by value when used as

12.2 Properties method arguments. In many situations, for instance generic


collection libraries, the code is written to handle reference
.NET properties are a metadata-level mechanism to asso- types. Fortunately, every value type can be represented as
ciate getter and/or setter methods with a single common an instance of a reference type. The Scala compiler will stat-
name. C# [14] introduces special syntax for denining prop- ically determine the need for such conversion and generate
erties. the appropriate code.
Scala's notion of value types does not extend to user-
public class Celsius { denable value types. Consequently, one cannot dene
private int d = 0; .NET value types in Scala. They have to be provided in
public int degree { an external .NET binary le called an assembly.

21
Structures. Value types are useful for representing Of course, Scala adopts a large part of the concepts and
lightweight objects. In C# they are called structures and syntactic conventions of Java [22] and C# [14]. Scala's way
are dened using special syntax. to express properties is loosely modelled after Sather [42].
From Smalltalk [21] comes the concept of a uniform ob-
struct Point { ject model. From Beta [30] comes the idea that everything
public Point(int x, int y) { this.x = x; this.y = y; } should be nestable, including classes. Scala's design of mix-
public int x, y; ins comes from object-oriented linear mixins [6], but denes
} mixin composition in a symmetric way, similar to what is
found in mixin modules [13, 24, 48] or traits [41]. Scala's
Once dened in a .NET assembly, structures can be used
abstract types have close resemblances to abstract types of
in Scala programs like regular reference types.
signatures in the module systems of ML [23] and OCaml [29],
def r(p: Point): double = Math.Sqrt(p.x*p.x + p.y*p.y); generalizing them to a context of rst-class components.
def dist(p1: Point, p2.Point): double = { For-comprehensions are based on Haskell's monad compre-
val p = new Point(p1.x - p2.x, p1.y - p2.y); hensions [44], even though their syntax more closely resem-
r(p) bles XQuery [3]. Views have been inuenced by Haskell's
} type classes [45]. They can be seen as an object-oriented
version of parametric type classes [37], but they are more
general in that instance declarations can be local and are
Enumerations. .NET has native support for type-safe scoped. Classboxes [2] provide the key benets of views in
enumerations. An enumeration type extends System.Enum a dynamically typed system. Unlike views, they also permit
and denes a value type, since System.Enum extends local rebinding so that class extensions can be selected using
System.ValueType. The members of an enumeration are dynamic dispatch.
named constants of any integral type (int, short, etc.) ex- In a sense, Scala represents a continuation of the work on
cept for char. Every enumeration denes a distinct type and Pizza [36]. Like Pizza, Scala compiles to the JVM, adding
its members cannot be used as values of the enumeration's higher-order functions, generics and pattern matching, con-
underlying type; this is only possible with an explicit cast. structs which have been originally developed in the func-
In C#, an enumeration is dened using special syntax. tional programming community. Whereas Pizza is back-
wards compatible with Java, Scala's aim is only to be in-
public enum Color {
teroperable, leaving more degrees of freedom in its design.
Red, Green, Blue
Scala's aim to provide advanced constructs for the ab-
}
straction and composition of components is shared by sev-

When a .NET enumeration is used in a Scala program, eral recent research eorts. Abstract types are a more con-

it is treated as a reference type. Its members are seen as servative construction to get most (but not all) of the ben-

static elds that have the type of the enumeration. ets of virtual classes in gbeta [16, 17]. Closely related are
also the delegation layers in FamilyJ [39] and work on nested
class Color extends System.Enum; inheritance for Java [32]. Jiazzi [31] is an extension to Java
object Color { that adds a module mechanism based on units, a powerful
val Red: Color; form of parametrized module. Jiazzi supports extensibility
val Green: Color; idioms similar to Scala, such as the ability to implement
val Blue: Color; mixins.
} The Nice programming language [4] is a recent object-
oriented language that is similar to Java, but has its her-
In a .NET assembly these elds are represented as lit- itage in ML≤ [5]. Nice includes multiple dispatch, open
erals. Literals have xed values which reside in the assem-
classes, and a restricted form of retroactive abstraction
bly metadata, and they cannot be referenced at runtime.
based on abstract interfaces. Nice does not support modular
Instead, the compiler inlines the value associated with the
implementation-side typechecking. While Nice and Scala are
eld.
languages which dier signicantly from Java, they both are
Every enumeration type is augmented with methods that
designed to interoperate with Java programs and libraries,
perform comparisons (==, !=, <, <=, >, >=) and bitwise logical
and their compiler targets the JVM.
operations (|, &, ^).
MultiJava [12] is a conservative extension of Java that

def isRed(c: Color): Boolean = (c == Color.Red); adds symmetric multiple dispatch and open classes. It pro-
vides alternative solutions to many of the problems that
However, such methods do not exist in the denition of Scala also addresses. For instance, multiple dispatch pro-
the enumeration. They are recognized by the compiler and vides a solution to the binary method problem, which is
implemented to perform the respective primitive operation addressed by abstract types in Scala. Open classes provide
on the numerical values associated with the members of the a solution to the external extensibility problem, which is
enumeration. solved by views in Scala. A feature only found in Multi-
Java is the possibility to dynamically add new methods to

13 Related Work
a class, since open classes are integrated with Java's regular
dynamic loading process. Conversely, only Scala allows to
delimit the scope of an external class extension in a program.
Scala's design is inuenced by many dierent languages and
OCaml and Moby[19] are two alternative designs that
research papers. The following enumeration of related work
combine functional and object-oriented programming using
lists the main design inuences.
static typing. Unlike Scala, these two languages start with
a rich functional language including a sophisticated module

22
system and then build on these a comparatively lightweight [3] S. Boag, D. Chamberlin, M. F. Fermandez, D. Flo-
mechanism for classes. rescu, J. Robie, and J. Simon. XQuery 1.0:
An XML Query Language. W3c recommenda-
tion, World Wide Web Consortium, November 2003.
14 Conclusion http://www.w3.org/TR/xquery/.

Scala is both a large and a reasonably small language. It


[4] D. Bonniot and B. Keller. The Nice's user's manual, 2003.
http://nice.sourceforge.net/NiceManual.pdf.
is a large language in the sense that it has a rich syntax
and type system, combining concepts from object-oriented [5] F. Bourdoncle and S. Merz. Type-checking Higher-Order
programming and functional programming. Hence, there Polymorphic Multi-Methods. In Conference Record of
are new constructs to be learned for users coming from ei- POPL '97: The 24th ACM SIGPLAN-SIGACT Sympo-
ther language community. Much of Scala's diversity is also sium on Principles of Programming Languages, pages 15
caused by the motivation to stay close to conventional lan- 17, Paris, France, 1997.
guages such as Java and C#, with the aim to ease adoption
[6] G. Bracha and W. Cook. Mixin-Based Inheritance. In
of Scala by users of these languages. N. Meyrowitz, editor, Proceedings of ECOOP '90, pages
Scala is also a reasonably small language, in the sense 303311, Ottawa, Canada, October 1990. ACM Press.
that it builds on a modest set of very general concepts. Many
source level constructs are syntactic sugar, which can be [7] T. Bray, J. Paoli, C. M. Sperberg-McQueen, E. Maler,
removed by encodings.
and F. Yergeau, eds. Extensible Markup Language
(XML) 1.0. W3C recommendation, World Wide
Generalizations such as the uniform object model allow
Web Consortium, February 2004. Available online
one to abstract from many dierent primitive types and op-
http://www.w3.org/TR/REC-xml-20040204/.
erations, delegating them to constructs in the Scala library.
Scala's specication and implementation also indicate [8] K. B. Bruce, M. Odersky, and P. Wadler. A Statically Safe
that its complexity is manageable. The current Scala com- Alternative to Virtual Types. Lecture Notes in Computer
piler frontend is roughly as large as Sun's Java 1.4 frontend Science, 1445, 1998. Proc. ESOP 1998.
 we expect to decrease its size signicantly by rewriting
[9] K. B. Bruce, A. Schuett, and R. van Gent. PolyTOIL: A
it completely in Scala. The current Scala specication [34]
Type-Safe Polymorphic Object-Oriented Language. In Pro-
(about 100 pages) is considerably smaller than the current ceedings of ECOOP '95, LNCS 952, pages 2751, Aarhus,
Java 1.4 specication [22] (about 400 pages). These sizes Denmark, August 1995. Springer-Verlag.
are hard to compare, though, as the Scala specication still
lacks the level of maturity of the Java specication, and also [10] P. Canning, W. Cook, W. Hill, W. Oltho, and J. Mitchell.
uses shorter formulas in many places where the Java speci-
F-Bounded Quantication for Object-Oriented Program-
ming. In Proc. of 4th Int. Conf. on Functional Programming
cation uses prose.
and Computer Architecture, FPCA'89, London, pages 273
Scala has been released publicly on the JVM platform in
280, New York, Sep 1989. ACM Pres.
January 2004 and on the .NET platform in June 2004. The
implementation is complete except for run-time types; these [11] L. Cardelli, S. Martini, J. C. Mitchell, and A. Scedrov. An
are expected for the end of 2004. In the future, we intend Extension of System F with Subtyping. Information and
to experiment with more rened type systematic support for Computation, 109(12):456, 1994.
XML, constructor polymorphism, and interfaces to database
[12] C. Clifton, G. T. Leavens, C. Chambers, and T. Millstein.
query languages, and to extend the current set of standard MultiJava: Design Rationale, Compiler Implementation,
Scala libraries. We also plan to continue work on formalizing and User Experience. Technical Report 04-01, Iowa State
key aspects of of the language and on developing compiler University, Dept. of Computer Science, Jan 2004.
optimizations targeted at its constructs.
[13] D. Duggan. Mixin modules. In ACM SIGPLAN Interna-
tional Conference on Functional Programming, 1996.
Acknowledgments Scala's design and implementation
was partially supported by grants from the Swiss National [14] ECMA. C# Language Specication. Technical Report Stan-
Fund under project NFS 21-61825, the Swiss National Com- dard ECMA-334, 2nd Edition, European Computer Manu-
petence Center for Research MICS, Microsoft Research, and facturers Association, December 2002.
the Hasler Foundation. We also thank Gilad Bracha, Erik
[15] ECMA. Common Language Infrastructure. Technical Re-
Ernst, Benjamin Pierce, Mads Torgersen, and Philip Wadler port Standard ECMA-335, 2nd Edition, European Com-
for useful discussions on aspects of the language. puter Manufacturers Association, December 2002.
[16] E. Ernst. Family polymorphism. In Proceedings of the Eu-
ropean Conference on Object-Oriented Programming, pages
303326, Budapest, Hungary, 2001.
References [17] E. Ernst. Higher-Order Hierarchies. In L. Cardelli, editor,
Proceedings ECOOP 2003, LNCS 2743, pages 303329, Hei-
[1] J. Armstrong, R. Virding, C. Wikström, and delberg, Germany, July 2003. Springer-Verlag.
M. Williams. Concurrent Programming in Erlang.
Prentice-Hall, second edition, 1996.
[18] D. C. Fallside, editor. XML Schema. W3C recommendation,
World Wide Web Consortium, May 2001. Available online
[2] A. Bergel, S. Ducasse, and R. Wuyts. Classboxes: A http://www.w3.org/TR/xmlschema-0/.
Minimal Module Model Supporting Local Rebinding.
[19] K. Fisher and J. H. Reppy. The Design of a Class Mecha-
In Proc. JMLC 2003, volume 2789 of Springer LNCS, nism for Moby. In SIGPLAN Conference on Programming
pages 122131, 2003. Language Design and Implementation, pages 3749, 1999.

23
[20] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design [38] M. Odersky, C. Zenger, and M. Zenger. Colored Local Type
Patterns: Elements of Reusable Object-Oriented Software. Inference. In Proceedings of the 28th ACM Symposium on
Addison Wesley, Massachusetts, 1994. Principles of Programming Languages, pages 4153, Lon-
don, UK, January 2001.
[21] A. Goldberg and D. Robson. Smalltalk-80: The Language
and Its Implementation. Addison-Wesley, 1983. [39] K. Ostermann. Dynamically Composable Collaborations
with Delegation Layers. In Proceedings of the 16th Euro-
[22] J. Gosling, B. Joy, G. Steele, and G. Bracha. The Java Lan- pean Conference on Object-Oriented Programming, Malaga,
guage Specication. Java Series, Sun Microsystems, second Spain, 2002.
edition, 2000.
[40] B. C. Pierce and D. N. Turner. Local Type Inference. In
[23] R. Harper and M. Lillibridge. A Type-Theoretic Approach Proc. 25th ACM Symposium on Principles of Programming
to Higher-Order Modules with Sharing. In Proc. 21st ACM Languages, pages 252265, New York, NY, 1998.
Symposium on Principles of Programming Languages, Jan-
uary 1994. [41] N. Schärli, S. Ducasse, O. Nierstrasz, and A. Black. Traits:
Composable Units of Behavior. In Proceedings of the
[24] T. Hirschowitz and X. Leroy. Mixin Modules in a Call-by- 17th European Conference on Object-Oriented Program-
Value Setting. In European Symposium on Programming, ming, Darmstadt, Germany, June 2003.
pages 620, 2002.
[42] D. Stoutamire and S. M. Omohundro. The Sather 1.0 Spec-
[25] A. Igarashi, B. Pierce, and P. Wadler. Featherweight Java: ication. Technical Report TR-95-057, International Com-
A minimal core calculus for Java and GJ. In Proceedings of puter Science Institute, Berkeley, 1995.
the Conference on Object-Oriented Programming, Systems,
Languages & Applications, volume 34(10), pages 132146, [43] M. Torgersen, C. P. Hansen, E. Ernst, P. vod der Ahé,
1999. G. Bracha, and N. Gafter. Adding Wildcards to the Java
Programming Language. In Proceedings SAC 2004, Nicosia,
[26] A. Igarashi and M. Viroli. Variant Parametric Types: A Cyprus, March 2004.
Flexible Subtyping Scheme for Generics. In Proceedings of
the Sixteenth European Conference on Object-Oriented Pro- [44] P. Wadler. The Essence of Functional Programming. In
gramming (ECOOP2002), pages 441469, June 2002. Proc.19th ACM Symposium on Principles of Programming
Languages, pages 114, January 1992.
[27] M. P. Jones. Using parameterized signatures to express mod-
ular structure. In Proceedings of the 23rd ACM Sympo- [45] P. Wadler and S. Blott. How to make ad-hoc Polymorphism
sium on Principles of Programming Languages, pages 68 less ad-hoc. In Proc. 16th ACM Symposium on Principles
78. ACM Press, 1996. of Programming Languages, pages 6076, January 1989.
[28] R. Keller and U. Hölzle. Binary Component Adaptation. In [46] M. Zenger. Erweiterbare Übersetzer. Master's thesis, Uni-
Proceedings ECOOP, Springer LNCS 1445, pages 307329, versity of Karlsruhe, August 1998.
1998.
[47] M. Zenger. Type-Safe Prototype-Based Component Evolu-
[29] X. Leroy. Manifest Types, Modules and Separate Compila- tion. In Proceedings of the European Conference on Object-
tion. In Proc. 21st ACM Symposium on Principles of Pro- Oriented Programming, Málaga, Spain, June 2002.
gramming Languages, pages 109122, January 1994.
[48] M. Zenger. Programming Language Abstractions for Ex-
[30] O. L. Madsen and B. Moeller-Pedersen. Virtual Classes - A tensible Software Components. PhD thesis, Department of
Powerful Mechanism for Object-Oriented Programming. In Computer Science, EPFL, Lausanne, March 2004.
Proc. OOPSLA'89, pages 397406, October 1989.
[49] M. Zenger and M. Odersky. Extensible Algebraic Datatypes
[31] S. McDirmid, M. Flatt, and W. Hsieh. Jiazzi: New-age with Defaults. In Proceedings of the International Confer-
Components for Old-Fashioned Java. In Proc. of OOPSLA, ence on Functional Programming, Firenze, Italy, September
October 2001. 2001.
[32] N. Nystrom, S. Chong, and A. Myers. Scalable Extensibility
via Nested Inheritance. In Proc. OOPSLA, Oct 2004.
[33] Oasis. RELAX NG. See http://www.oasis-open.org/.
[34] M. Odersky and al. The Scala Language Specication. Tech-
nical report, EPFL Lausanne, Switzerland, Jan. 2004. Avail-
able online http://scala.epfl.ch.
[35] M. Odersky, V. Cremet, C. Röckl, and M. Zenger. A
nominal theory of objects with dependent types. In Proc.
ECOOP'03, Springer LNCS 2743, July 2003.
[36] M. Odersky and P. Wadler. Pizza into Java: Translating
theory into practice. In Proc. 24th ACM Symposium on
Principles of Programming Languages, pages 146159, Jan-
uary 1997.
[37] M. Odersky, P. Wadler, and M. Wehr. A Second Look at
Overloading. In Proc. ACM Conf. on Functional Program-
ming and Computer Architecture, pages 135146, June 1995.

24

You might also like