*** empty log message ***

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@2418 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2004-01-20 11:50:36 +00:00
parent cf69c6449c
commit bcfd151a69
6 changed files with 77 additions and 576 deletions

View File

@ -23,8 +23,8 @@ interesting programming techniques. The present informal exposition is
meant to be complemented by the Java Language Reference Manual which meant to be complemented by the Java Language Reference Manual which
specifies Scala in a more detailed and precise way. specifies Scala in a more detailed and precise way.
\paragraph{Acknowledgement} \paragraph{Acknowledgment}
We owe a great dept to Sussman and Abelson's wonderful book We owe a great debt to Abelson's and Sussman's wonderful book
``Structure and Interpretation of Computer ``Structure and Interpretation of Computer
Programs''\cite{abelson-sussman:structure}. Many of their examples and Programs''\cite{abelson-sussman:structure}. Many of their examples and
exercises are also present here. Of course, the working language has exercises are also present here. Of course, the working language has
@ -86,7 +86,7 @@ instance, the name of the array \code{a} is visible in functions
parameter to them. parameter to them.
\end{itemize} \end{itemize}
So far, Scala looks like a fairly conventional language with some So far, Scala looks like a fairly conventional language with some
syntactic pecularities. In fact it is possible to write programs in a syntactic peculiarities. In fact it is possible to write programs in a
conventional imperative or object-oriented style. This is important conventional imperative or object-oriented style. This is important
because it is one of the things that makes it easy to combine Scala because it is one of the things that makes it easy to combine Scala
components with components written in mainstream languages such as components with components written in mainstream languages such as
@ -106,7 +106,7 @@ def sort(xs: List[int]): List[int] = {
\end{lstlisting} \end{lstlisting}
The functional program works with lists instead of arrays.\footnote{In The functional program works with lists instead of arrays.\footnote{In
a future complete implemenetation of Scala, we could also have used arrays a future complete implementation of Scala, we could also have used arrays
instead of lists, but at the moment arrays do not yet support instead of lists, but at the moment arrays do not yet support
\code{filter} and \code{:::}.} \code{filter} and \code{:::}.}
It captures the essence of the quicksort algorithm in a concise way: It captures the essence of the quicksort algorithm in a concise way:
@ -114,7 +114,7 @@ It captures the essence of the quicksort algorithm in a concise way:
\item Pick an element in the middle of the list as a pivot. \item Pick an element in the middle of the list as a pivot.
\item Partition the lists into two sub-lists containing elements that \item Partition the lists into two sub-lists containing elements that
are less than, respectively greater than the pivot element, and a are less than, respectively greater than the pivot element, and a
third list which contains elements equal to privot. third list which contains elements equal to pivot.
\item Sort the first two sub-lists by a recursive invocation of \item Sort the first two sub-lists by a recursive invocation of
the sort function.\footnote{This is not quite what the imperative algorithm does; the sort function.\footnote{This is not quite what the imperative algorithm does;
the latter partitions the array into two sub-arrays containing elements the latter partitions the array into two sub-arrays containing elements
@ -328,7 +328,7 @@ on one item. Objects of this class are created by indicating
\end{itemize} \end{itemize}
The process behavior is defined by its \code{run} method. That method The process behavior is defined by its \code{run} method. That method
repeatedly selects (using \code{receiveWithin}) a message and reacts to it, repeatedly selects (using \code{receiveWithin}) a message and reacts to it,
until the auction is closed, which is signalled by a \code{TIMEOUT} until the auction is closed, which is signaled by a \code{TIMEOUT}
message. Before finally stopping, it stays active for another period message. Before finally stopping, it stays active for another period
determined by the \code{timeToShutdown} constant and replies to determined by the \code{timeToShutdown} constant and replies to
further offers that the auction is closed. further offers that the auction is closed.
@ -632,7 +632,7 @@ def sqrtIter(guess: double, x: double): double =
else sqrtIter(improve(guess, x), x); else sqrtIter(improve(guess, x), x);
\end{lstlisting} \end{lstlisting}
Note that \code{sqrtIter} calls itself recursively. Loops in Note that \code{sqrtIter} calls itself recursively. Loops in
imperative programs can always be modelled by recursion in functional imperative programs can always be modeled by recursion in functional
programs. programs.
Note also that the definition of \code{sqrtIter} contains a return Note also that the definition of \code{sqrtIter} contains a return
@ -654,7 +654,7 @@ def isGoodEnough(guess: double, x: double) =
abs(square(guess) - x) < 0.001; abs(square(guess) - x) < 0.001;
\end{lstlisting} \end{lstlisting}
Finally, the \code{sqrt} function itself is defined by an aplication Finally, the \code{sqrt} function itself is defined by an application
of \code{sqrtIter}. of \code{sqrtIter}.
\begin{lstlisting} \begin{lstlisting}
def sqrt(x: double) = sqrtIter(1.0, x); def sqrt(x: double) = sqrtIter(1.0, x);
@ -800,7 +800,7 @@ executed in constant space.
By contrast, the recursive call in \code{factorial} is followed by a By contrast, the recursive call in \code{factorial} is followed by a
multiplication. Hence, a new stack frame is allocated for the multiplication. Hence, a new stack frame is allocated for the
recursive instance of factorial, and is decallocated after that recursive instance of factorial, and is deallocated after that
instance has finished. The given formulation of the factorial function instance has finished. The given formulation of the factorial function
is not tail-recursive; it needs space proportional to its input is not tail-recursive; it needs space proportional to its input
parameter for its execution. parameter for its execution.
@ -810,7 +810,7 @@ More generally, if the last action of a function is a call to another
both functions. Such calls are called ``tail calls''. In principle, both functions. Such calls are called ``tail calls''. In principle,
tail calls can always re-use the stack frame of the calling function. tail calls can always re-use the stack frame of the calling function.
However, some run-time environments (such as the Java VM) lack the However, some run-time environments (such as the Java VM) lack the
primititives to make stack frame re-use for tail calls efficient. A primitives to make stack frame re-use for tail calls efficient. A
production quality Scala implementation is therefore only required to production quality Scala implementation is therefore only required to
re-use the stack frame of a directly tail-recursive function whose re-use the stack frame of a directly tail-recursive function whose
last action is a call to itself. Other tail calls might be optimized last action is a call to itself. Other tail calls might be optimized
@ -1377,7 +1377,7 @@ integers, as well as a private field \code{g} which contains the
\code{gcd} of the constructor arguments. These members are inaccessible \code{gcd} of the constructor arguments. These members are inaccessible
outside class \code{Rational}. They are used in the implementation of outside class \code{Rational}. They are used in the implementation of
the class to eliminate common factors in the constructor arguments in the class to eliminate common factors in the constructor arguments in
order to ensure that nominator and denominator are always in order to ensure that numerator and denominator are always in
normalized form. normalized form.
\paragraph{Creating and Accessing Objects} \paragraph{Creating and Accessing Objects}
@ -1478,7 +1478,7 @@ that clients do not have to be rewritten because of that change.
Consider the task of writing a class for sets of integer numbers with Consider the task of writing a class for sets of integer numbers with
two operations, \code{incl} and \code{contains}. \code{(s incl x)} two operations, \code{incl} and \code{contains}. \code{(s incl x)}
should return a new set which contains the element \code{x} togther should return a new set which contains the element \code{x} together
with all the elements of set \code{s}. \code{(s contains x)} should with all the elements of set \code{s}. \code{(s contains x)} should
return true if the set \code{s} contains the element \code{x}, and return true if the set \code{s} contains the element \code{x}, and
should return \code{false} otherwise. The interface of such sets is should return \code{false} otherwise. The interface of such sets is
@ -1750,7 +1750,7 @@ trait Nat {
def - (that: Nat): Nat; def - (that: Nat): Nat;
} }
\end{lstlisting} \end{lstlisting}
To implement the operations of class \code{Nat}, we define a subobject To implement the operations of class \code{Nat}, we define a sub-object
\code{Zero} and a subclass \code{Succ} (for successor). Each number \code{Zero} and a subclass \code{Succ} (for successor). Each number
\code{N} is represented as \code{N} applications of the \code{Succ} \code{N} is represented as \code{N} applications of the \code{Succ}
constructor to \code{Zero}: constructor to \code{Zero}:
@ -2027,7 +2027,7 @@ would be added. Hence, one can now construct expression trees a bit more concise
Sum(Sum(Number(1), Number(2)), Number(3)) Sum(Sum(Number(1), Number(2)), Number(3))
\end{lstlisting} \end{lstlisting}
\item Case classes and case objects \item Case classes and case objects
implicity come with implementations of methods implicitly come with implementations of methods
\code{toString}, \code{equals} and \code{hashCode}, which override the \code{toString}, \code{equals} and \code{hashCode}, which override the
methods with the same name in class \code{AnyRef}. The implementation methods with the same name in class \code{AnyRef}. The implementation
of these methods takes in each case the structure of a member of a of these methods takes in each case the structure of a member of a
@ -2056,7 +2056,7 @@ methods. It computes a hash code from the case class constructor name
and the hash codes of the constructor arguments, instead of from the object's and the hash codes of the constructor arguments, instead of from the object's
address, which is what the as the default implementation of \code{hashCode} does. address, which is what the as the default implementation of \code{hashCode} does.
\item \item
Case classes implicity come with nullary accessor methods which Case classes implicitly come with nullary accessor methods which
retrieve the constructor arguments. retrieve the constructor arguments.
In our example, \code{Number} would obtain an accessor method In our example, \code{Number} would obtain an accessor method
\begin{lstlisting} \begin{lstlisting}
@ -2418,7 +2418,7 @@ val s = new EmptySet[java.io.File]
$\mbox{\sl parameter bound}$ Ord[java.io.File]. $\mbox{\sl parameter bound}$ Ord[java.io.File].
\end{lstlisting} \end{lstlisting}
To conclude the discussion of type parameter To conclude the discussion of type parameter
bounds, here is the defintion of trait \code{Ord} in scala. bounds, here is the definition of trait \code{Ord} in scala.
\begin{lstlisting} \begin{lstlisting}
package scala; package scala;
trait Ord[t <: Ord[t]]: t { trait Ord[t <: Ord[t]]: t {
@ -2519,7 +2519,7 @@ class Array[+a] {
$\mbox{\sl appears in contravariant position.}$ $\mbox{\sl appears in contravariant position.}$
} }
\end{lstlisting} \end{lstlisting}
So far, so good. Intuitively, the compiler was correect in rejecting So far, so good. Intuitively, the compiler was correct in rejecting
the \code{update} method in a co-variant class because \code{update} the \code{update} method in a co-variant class because \code{update}
potentially changes state, and therefore undermines the soundness of potentially changes state, and therefore undermines the soundness of
co-variant subtyping. co-variant subtyping.
@ -2580,7 +2580,7 @@ often suggest a useful generalization of the contested method.
\section{Least Types} \section{Least Types}
Scala does not allow one to parameterize objects with types. That's Scala does not allow one to parameterize objects with types. That's
why we orginally defined a generic class \code{EmptyStack[a]}, even why we originally defined a generic class \code{EmptyStack[a]}, even
though a single value denoting empty stacks of arbitrary type would though a single value denoting empty stacks of arbitrary type would
do. For co-variant stacks, however, one can use the following idiom: do. For co-variant stacks, however, one can use the following idiom:
\begin{lstlisting} \begin{lstlisting}
@ -2677,14 +2677,14 @@ follows.
\begin{lstlisting} \begin{lstlisting}
def divmod(x: int, y: int) = Pair(x / y, x % y) def divmod(x: int, y: int) = Pair(x / y, x % y)
\end{lstlisting} \end{lstlisting}
How are elements of tuples acessed? Since tuples are case classes, How are elements of tuples accessed? Since tuples are case classes,
there are two possibilities. One can either access a tuple's fields there are two possibilities. One can either access a tuple's fields
using the names of the constructor parameters \lstinline@_$i$@, as in the following example: using the names of the constructor parameters \lstinline@_$i$@, as in the following example:
\begin{lstlisting} \begin{lstlisting}
val xy = divmod(x, y); val xy = divmod(x, y);
System.out.println("quotient: " + x._1 + ", rest: " + x._2); System.out.println("quotient: " + x._1 + ", rest: " + x._2);
\end{lstlisting} \end{lstlisting}
Or one uses pattern matching on tuples, as in the following erample: Or one uses pattern matching on tuples, as in the following example:
\begin{lstlisting} \begin{lstlisting}
divmod(x, y) match { divmod(x, y) match {
case Pair(n, d) => case Pair(n, d) =>
@ -3153,7 +3153,7 @@ computation over lists, like:
\item extracting from a list all elements satisfying a criterion. \item extracting from a list all elements satisfying a criterion.
\item combine the elements of a list using some operator. \item combine the elements of a list using some operator.
\end{itemize} \end{itemize}
Functional programming languages enable programmers to write eneral Functional programming languages enable programmers to write general
functions which implement patterns like this by means of higher order functions which implement patterns like this by means of higher order
functions. We now discuss a set of commonly used higher-order functions. We now discuss a set of commonly used higher-order
functions, which are implemented as methods in class \code{List}. functions, which are implemented as methods in class \code{List}.
@ -3176,7 +3176,7 @@ abstract class List[a] { ...
case x :: xs => f(x) :: xs.map(f) case x :: xs => f(x) :: xs.map(f)
} }
\end{lstlisting} \end{lstlisting}
Using \code{map}, \code{scaleList} can be more consisely written as follows. Using \code{map}, \code{scaleList} can be more concisely written as follows.
\begin{lstlisting} \begin{lstlisting}
def scaleList(xs: List[double], factor: double) = def scaleList(xs: List[double], factor: double) =
xs map (x => x * factor) xs map (x => x * factor)
@ -3237,7 +3237,7 @@ This pattern is generalized to the \code{filter} method of class \code{List}:
case x :: xs => if (p(x)) x :: xs.filter(p) else xs.filter(p) case x :: xs => if (p(x)) x :: xs.filter(p) else xs.filter(p)
} }
\end{lstlisting} \end{lstlisting}
Using \code{filter}, \code{posElems} can be more consisely written as Using \code{filter}, \code{posElems} can be more concisely written as
follows. follows.
\begin{lstlisting} \begin{lstlisting}
def posElems(xs: List[int]): List[int] = def posElems(xs: List[int]): List[int] =
@ -3260,7 +3260,7 @@ To illustrate the use of \code{forall}, consider the question whether
a number if prime. Remember that a number $n$ is prime of it can be a number if prime. Remember that a number $n$ is prime of it can be
divided without remainder only by one and itself. The most direct divided without remainder only by one and itself. The most direct
translation of this definition would test that $n$ divided by all translation of this definition would test that $n$ divided by all
numbers from 2 upto and excluding itself gives a non-zero numbers from 2 up to and excluding itself gives a non-zero
remainder. This list of numbers can be generated using a function remainder. This list of numbers can be generated using a function
\code{List.range} which is defined in object \code{List} as follows. \code{List.range} which is defined in object \code{List} as follows.
\begin{lstlisting} \begin{lstlisting}
@ -3270,7 +3270,7 @@ object List { ...
if (from >= end) Nil else from :: range(from + 1, end); if (from >= end) Nil else from :: range(from + 1, end);
\end{lstlisting} \end{lstlisting}
For example, \code{List.range(2, n)} For example, \code{List.range(2, n)}
generates the list of all integers from 2 upto and excluding $n$. generates the list of all integers from 2 up to and excluding $n$.
The function \code{isPrime} can now simply be defined as follows. The function \code{isPrime} can now simply be defined as follows.
\begin{lstlisting} \begin{lstlisting}
def isPrime(n: int) = def isPrime(n: int) =
@ -3301,7 +3301,7 @@ def product(xs: List[int]): int = xs match {
case y :: ys => y * product(ys) case y :: ys => y * product(ys)
} }
\end{lstlisting} \end{lstlisting}
But we can also use the generaliztion of this program scheme embodied But we can also use the generalization of this program scheme embodied
in the \code{reduceLeft} method of class \code{List}. This method in the \code{reduceLeft} method of class \code{List}. This method
inserts a given binary operator between adjacent elements of a given list. inserts a given binary operator between adjacent elements of a given list.
E.g.\ E.g.\
@ -3919,7 +3919,7 @@ constructions for dealing with lists. But sometimes the level of
abstraction required by these functions makes a program hard to abstraction required by these functions makes a program hard to
understand. understand.
To help understandbility, Scala has a special notation which To help understandability, Scala has a special notation which
simplifies common patterns of applications of higher-order functions. simplifies common patterns of applications of higher-order functions.
This notation builds a bridge between set-comprehensions in This notation builds a bridge between set-comprehensions in
mathematics and for-loops in imperative languages such as C or mathematics and for-loops in imperative languages such as C or
@ -3977,15 +3977,15 @@ be written as follows.
For-comprehensions are especially useful for solving combinatorial For-comprehensions are especially useful for solving combinatorial
puzzles. An example of such a puzzle is the 8-queens problem: Given a puzzles. An example of such a puzzle is the 8-queens problem: Given a
standard chessboard, place 8 queens such that no queen is in check from any standard chess-board, place 8 queens such that no queen is in check from any
other (a queen can check another piece if they are on the same other (a queen can check another piece if they are on the same
column, row, or diagional). We will now develop a solution to this column, row, or diagonal). We will now develop a solution to this
problem, generalizing it to chessboards of arbitrary size. Hence, the problem, generalizing it to chess-boards of arbitrary size. Hence, the
problem is to place $n$ queens on a chessboard of size $n \times n$. problem is to place $n$ queens on a chess-board of size $n \times n$.
To solve this problem, note that we need to place a queen in each row. To solve this problem, note that we need to place a queen in each row.
So we could place queens in successive rows, each time checking that a So we could place queens in successive rows, each time checking that a
newly placed queen is not in queck from any other queens that have newly placed queen is not in check from any other queens that have
already been placed. In the course of this search, it might arrive already been placed. In the course of this search, it might arrive
that a queen to be placed in row $k$ would be in check in all fields that a queen to be placed in row $k$ would be in check in all fields
of that row from queens in row $1$ to $k-1$. In that case, we need to of that row from queens in row $1$ to $k-1$. In that case, we need to
@ -4006,7 +4006,7 @@ element for each solution.
Now, to place the $k$'the queen, we generate all possible extensions Now, to place the $k$'the queen, we generate all possible extensions
of each previous solution by one more queen. This yields another list of each previous solution by one more queen. This yields another list
of solution lists, this time of length $k$. We continue the process of solution lists, this time of length $k$. We continue the process
until we have reached solutions of the size of the chessboard $n$. until we have reached solutions of the size of the chess-board $n$.
This algorithmic idea is embodied in function \code{placeQueens} below: This algorithmic idea is embodied in function \code{placeQueens} below:
\begin{lstlisting} \begin{lstlisting}
def queens(n: int): List[List[int]] = { def queens(n: int): List[List[int]] = {
@ -4041,7 +4041,7 @@ Here is a small example database:
\begin{lstlisting} \begin{lstlisting}
val books: List[Book] = List( val books: List[Book] = List(
Book("Structure and Interpretation of Computer Programs", Book("Structure and Interpretation of Computer Programs",
List("Abelson, Harald", "Sussman, Gerald J.")), List("Abelson, Harold", "Sussman, Gerald J.")),
Book("Principles of Compiler Design", Book("Principles of Compiler Design",
List("Aho, Alfred", "Ullman, Jeffrey")), List("Aho, Alfred", "Ullman, Jeffrey")),
Book("Programming in Modula-2", Book("Programming in Modula-2",
@ -4184,7 +4184,7 @@ For-comprehensions resemble for-loops in imperative languages, except
that they produce a list of results. Sometimes, a list of results is that they produce a list of results. Sometimes, a list of results is
not needed but we would still like the flexibility of generators and not needed but we would still like the flexibility of generators and
filters in iterations over lists. This is made possible by a variant filters in iterations over lists. This is made possible by a variant
of the for-comprehension syntax, which excpresses for-loops: of the for-comprehension syntax, which expresses for-loops:
\begin{lstlisting} \begin{lstlisting}
for ( $s$ ) $e$ for ( $s$ ) $e$
\end{lstlisting} \end{lstlisting}
@ -4270,7 +4270,7 @@ theory underlying functional programming.
In this chapter, we introduce functions with side effects and study In this chapter, we introduce functions with side effects and study
their behavior. We will see that as a consequence we have to their behavior. We will see that as a consequence we have to
fundamenatlly modify up the substitution model of computation which we fundamentally modify up the substitution model of computation which we
employed so far. employed so far.
\section{Stateful Objects} \section{Stateful Objects}
@ -4308,7 +4308,7 @@ In Scala, every defined variable has to be initialized at the point of
its definition. For instance, the statement ~\code{var x: int;}~ is its definition. For instance, the statement ~\code{var x: int;}~ is
{\em not} regarded as a variable definition, because the initializer {\em not} regarded as a variable definition, because the initializer
is missing\footnote{If a statement like this appears in a class, it is is missing\footnote{If a statement like this appears in a class, it is
instead regarded as a variable declaration, which introcuces instead regarded as a variable declaration, which introduces
abstract access methods for the variable, but does not associate these abstract access methods for the variable, but does not associate these
methods with a piece of state.}. If one does not know, or does not methods with a piece of state.}. If one does not know, or does not
care about, the appropriate initializer, one can use a wildcard care about, the appropriate initializer, one can use a wildcard
@ -4739,7 +4739,7 @@ inserts the pair \code{(curtime + delay, action)} into the
Pair(actiontime, action) :: ag Pair(actiontime, action) :: ag
case (first @ Pair(time, act)) :: ag1 => case (first @ Pair(time, act)) :: ag1 =>
if (actiontime < time) Pair(actiontime, action) :: ag if (actiontime < time) Pair(actiontime, action) :: ag
else first :: insert(ag1) else first :: insert(ag1)
} }
agenda = insert(agenda) agenda = insert(agenda)
} }
@ -4801,7 +4801,7 @@ sum 15 new_value = false
\section{Summary} \section{Summary}
We have seen in this chapter the constructs that let us model state in We have seen in this chapter the constructs that let us model state in
Scala -- these are variables, assignments, abd imperative control Scala -- these are variables, assignments, and imperative control
structures. State and Assignment complicate our mental model of structures. State and Assignment complicate our mental model of
computation. In particular, referential transparency is lost. On the computation. In particular, referential transparency is lost. On the
other hand, assignment gives us new ways to formulate programs other hand, assignment gives us new ways to formulate programs
@ -4812,8 +4812,8 @@ functional programming or programming with assignments works best.
The previous chapters have introduced variables, assignment and The previous chapters have introduced variables, assignment and
stateful objects. We have seen how real-world objects that change stateful objects. We have seen how real-world objects that change
with time can be modelled by changing the state of variables in a with time can be modeled by changing the state of variables in a
computation. Time changes in the real world thus are modelled by time computation. Time changes in the real world thus are modeled by time
changes in program execution. Of course, such time changes are usually changes in program execution. Of course, such time changes are usually
stretched out or compressed, but their relative order is the same. stretched out or compressed, but their relative order is the same.
This seems quite natural, but there is a also price to pay: Our simple This seems quite natural, but there is a also price to pay: Our simple
@ -4822,7 +4822,7 @@ longer applicable once we introduce variables and assignment.
Is there another way? Can we model state change in the real world Is there another way? Can we model state change in the real world
using only immutable functions? Taking mathematics as a guide, the using only immutable functions? Taking mathematics as a guide, the
answer is clearly yes: A time-changing quantity is simply modelled by answer is clearly yes: A time-changing quantity is simply modeled by
a function \code{f(t)} with a time parameter \code{t}. The same can be a function \code{f(t)} with a time parameter \code{t}. The same can be
done in computation. Instead of overwriting a variable with successive done in computation. Instead of overwriting a variable with successive
values, we represent all these values as successive elements in a values, we represent all these values as successive elements in a
@ -4928,7 +4928,7 @@ This does not work for streams, where we require that the tail of a
stream should not be evaluated until it is demanded by a \code{tail} operation. stream should not be evaluated until it is demanded by a \code{tail} operation.
The argument why list-append \code{:::} cannot be adapted to streams is analogous. The argument why list-append \code{:::} cannot be adapted to streams is analogous.
Intstead of \code{x :: xs}, one uses \code{Stream.cons(x, xs)} for Instead of \code{x :: xs}, one uses \code{Stream.cons(x, xs)} for
constructing a stream with first element \code{x} and (unevaluated) constructing a stream with first element \code{x} and (unevaluated)
rest \code{xs}. Instead of \code{xs ::: ys}, one uses the operation rest \code{xs}. Instead of \code{xs ::: ys}, one uses the operation
\code{xs append ys}. \code{xs append ys}.
@ -4938,7 +4938,7 @@ rest \code{xs}. Instead of \code{xs ::: ys}, one uses the operation
Iterators are the imperative version of streams. Like streams, Iterators are the imperative version of streams. Like streams,
iterators describe potentially infinite lists. However, there is no iterators describe potentially infinite lists. However, there is no
data-structure which contains the elements of an iterator. Instead, data-structure which contains the elements of an iterator. Instead,
iterators aloow one to step through the sequence, using two abstract methods \code{next} and \code{hasNext}. iterators allow one to step through the sequence, using two abstract methods \code{next} and \code{hasNext}.
\begin{lstlisting} \begin{lstlisting}
trait Iterator[+a] { trait Iterator[+a] {
def hasNext: boolean; def hasNext: boolean;
@ -5035,7 +5035,7 @@ returns all elements of the original iterator that satisfy a criterion
\end{lstlisting} \end{lstlisting}
In fact, \code{filter} returns instances of a subclass of iterators In fact, \code{filter} returns instances of a subclass of iterators
which are ``buffered''. A \code{BufferedIterator} object is an which are ``buffered''. A \code{BufferedIterator} object is an
interator which has in addition a method \code{head}. This method iterator which has in addition a method \code{head}. This method
returns the element which would otherwise have been returned by returns the element which would otherwise have been returned by
\code{head}, but does not advance beyond that element. Hence, the \code{head}, but does not advance beyond that element. Hence, the
element returned by \code{head} is returned again by the next call to element returned by \code{head} is returned again by the next call to
@ -6514,9 +6514,9 @@ class ComputeServer(n: Int) {
val reply = new SyncVar[a](); val reply = new SyncVar[a]();
openJobs.write{ openJobs.write{
new Job { new Job {
type t = a; type t = a;
def task = p; def task = p;
def ret(x: a) = reply.set(x); def ret(x: a) = reply.set(x);
} }
} }
() => reply.get () => reply.get
@ -6604,7 +6604,7 @@ As a simple example of how mailboxes are used, consider a
one-place buffer: one-place buffer:
\begin{lstlisting} \begin{lstlisting}
class OnePlaceBuffer { class OnePlaceBuffer {
private val m = new MailBox; // An internal milbox private val m = new MailBox; // An internal mailbox
private case class Empty, Full(x: int); // Types of messages we deal with private case class Empty, Full(x: int); // Types of messages we deal with
m send Empty; // Initialization m send Empty; // Initialization
def write(x: int): unit = def write(x: int): unit =
@ -6662,10 +6662,10 @@ Otherwise, the message is appended to the linked list of sent messages.
if (s1 != null) { if (s1 != null) {
s.next = s1.next; s1.elem s.next = s1.next; s1.elem
} else { } else {
val r = insert(lastReceiver, new Receiver { val r = insert(lastReceiver, new Receiver {
def isDefined(msg: Any) = f.isDefinedAt(msg); def isDefined(msg: Any) = f.isDefinedAt(msg);
}); });
lastReceiver = r; lastReceiver = r;
r.elem.wait(); r.elem.wait();
r.elem.msg r.elem.msg
} }

View File

@ -44,7 +44,7 @@ varid ::= lower {letter $|$ digit} [`_' [id]]
id ::= upper {letter $|$ digit} [`_' [id]] id ::= upper {letter $|$ digit} [`_' [id]]
| varid | varid
| op | op
| ```string chars`'' | ```string chars`''
\end{lstlisting} \end{lstlisting}
There are three ways to form an identifier. First, an identifier can There are three ways to form an identifier. First, an identifier can
@ -54,7 +54,7 @@ letters and digits. This may be followed by an underscore
themselves make up an identifier. Second, an identifier can be start themselves make up an identifier. Second, an identifier can be start
with a special character followed by an arbitrary sequence of special with a special character followed by an arbitrary sequence of special
characters. Finally, an identifier may also be formed by an arbitrary characters. Finally, an identifier may also be formed by an arbitrary
string between backquotes (host systems may impose some restrictions string between back-quotes (host systems may impose some restrictions
on which strings are legal for identifiers). As usual, a longest on which strings are legal for identifiers). As usual, a longest
match rule applies. For instance, the string match rule applies. For instance, the string
@ -423,7 +423,7 @@ contravariant in their argument types.
\label{sec:synthetic-types} \label{sec:synthetic-types}
The types explained in the following do not denote sets of values, nor The types explained in the following do not denote sets of values, nor
do they appear explicitely in programs. They are introduced in this do they appear explicitly in programs. They are introduced in this
report as the internal types of defined identifiers. report as the internal types of defined identifiers.
\subsection{Method Types} \subsection{Method Types}
@ -693,7 +693,7 @@ transitive relation that satisfies the following conditions.
one has $\mbox{\code{scala.AllRef}} \conforms T$. one has $\mbox{\code{scala.AllRef}} \conforms T$.
\item A type variable or abstract type $t$ conforms to its upper bound and \item A type variable or abstract type $t$ conforms to its upper bound and
its lower bound conforms to $t$. its lower bound conforms to $t$.
\item A class type or parameterized type $c$ conforms to any of its basetypes, $b$. \item A class type or parameterized type $c$ conforms to any of its base-types, $b$.
\item A type projection \lstinline@$T$#$t$@ conforms to \lstinline@$U$#$t$@ if \item A type projection \lstinline@$T$#$t$@ conforms to \lstinline@$U$#$t$@ if
$T$ conforms to $U$. $T$ conforms to $U$.
\item A parameterized type ~\lstinline@$T$[$T_1 \commadots T_n$]@~ conforms to \item A parameterized type ~\lstinline@$T$[$T_1 \commadots T_n$]@~ conforms to
@ -767,7 +767,7 @@ class C extends A[C];
Then the types ~\lstinline@A[Any], A[A[Any]], A[A[A[Any]]], ...@~ form Then the types ~\lstinline@A[Any], A[A[Any]], A[A[A[Any]]], ...@~ form
a descending sequence of upper bounds for \code{B} and \code{C}. The a descending sequence of upper bounds for \code{B} and \code{C}. The
least upper bound would be the infinite limit of that sequence, which least upper bound would be the infinite limit of that sequence, which
does ot exist as a Scala type. Since cases like this are in general does not exist as a Scala type. Since cases like this are in general
impossible to detect, a Scala compiler is free to reject a term impossible to detect, a Scala compiler is free to reject a term
which has a type specified as a least upper or greatest lower bound, which has a type specified as a least upper or greatest lower bound,
and that bound would be more complex than some compiler-set and that bound would be more complex than some compiler-set
@ -840,7 +840,7 @@ or \code{short} is always implicitly converted to a value of type
If an expression $e$ has type $T$ where $T$ does not conform to the If an expression $e$ has type $T$ where $T$ does not conform to the
expected type $pt$ and $T$ has a member named \lstinline@coerce@ of type expected type $pt$ and $T$ has a member named \lstinline@coerce@ of type
$[]U$ where $U$ does comform to $pt$, then the expression is typed and evaluated is if it was $[]U$ where $U$ does conform to $pt$, then the expression is typed and evaluated is if it was
\lstinline@$e$.coerce@. \lstinline@$e$.coerce@.
@ -877,7 +877,7 @@ s_n$, if a simple name in $s_i$ refers to an entity defined by $s_j$
where $j \geq i$, then every non-empty statement between and including where $j \geq i$, then every non-empty statement between and including
$s_i$ and $s_j$ must be an import clause, $s_i$ and $s_j$ must be an import clause,
or a function, type, class, or object definition. It may not be or a function, type, class, or object definition. It may not be
a value definition, a variable defninition, or an expression. a value definition, a variable definition, or an expression.
\comment{ \comment{
Every basic definition may introduce several defined names, separated Every basic definition may introduce several defined names, separated
@ -914,7 +914,7 @@ the type definition
\comment{ \comment{
If an element in such a sequence introduces only the defined name, If an element in such a sequence introduces only the defined name,
possibly with some type or value parameters, but leaves out any possibly with some type or value parameters, but leaves out any
aditional parts in the definition, then those parts are implicitly additional parts in the definition, then those parts are implicitly
copied from the next subsequent sequence element which consists of copied from the next subsequent sequence element which consists of
more than just a defined name and parameters. Examples: more than just a defined name and parameters. Examples:
\begin{itemize} \begin{itemize}
@ -1360,7 +1360,7 @@ The last value parameter of a parameter section may be suffixed by
if a method $m$ with type ~\lstinline@($T_1 \commadots T_n, S$*)$U$@~ if a method $m$ with type ~\lstinline@($T_1 \commadots T_n, S$*)$U$@~
is applied to arguments $(e_1 \commadots e_k)$ where $k \geq n$, then is applied to arguments $(e_1 \commadots e_k)$ where $k \geq n$, then
$m$ is taken in that application to have type $(T_1 \commadots T_n, S $m$ is taken in that application to have type $(T_1 \commadots T_n, S
\commadots S)U$, with $k - n$ occurences of type $S$. \commadots S)U$, with $k - n$ occurrences of type $S$.
\todo{Change to ???: If the method \todo{Change to ???: If the method
is converted to a function type instead of being applied immediately, is converted to a function type instead of being applied immediately,
a repeated parameter \lstinline@$T$*@ is taken to be ~\lstinline@scala.Seq[$T$]@~ a repeated parameter \lstinline@$T$*@ is taken to be ~\lstinline@scala.Seq[$T$]@~
@ -1601,7 +1601,7 @@ class F extends B with D with E;
The mixin base classes and base classes of classes \code{A-F} are given in The mixin base classes and base classes of classes \code{A-F} are given in
the following table: the following table:
\begin{quote}\begin{tabular}{|l|l|l|} \hline \begin{quote}\begin{tabular}{|l|l|l|} \hline
\ & Mixin base classses & Base classes \\ \hline \ & Mixin base classes & Base classes \\ \hline
A & A & A, ScalaObject, AnyRef, Any \\ A & A & A, ScalaObject, AnyRef, Any \\
B & B & B, A, ScalaObject, AnyRef, Any \\ B & B & B, A, ScalaObject, AnyRef, Any \\
C & C & C, A, ScalaObject, AnyRef, Any \\ C & C & C, A, ScalaObject, AnyRef, Any \\
@ -1610,7 +1610,7 @@ E & C, D, E & E, B, C, D, A, ScalaObject, AnyRef, Any \\
F & C, D, E, F & F, B, D, E, C, A, ScalaObject, AnyRef, Any \\ \hline F & C, D, E, F & F, B, D, E, C, A, ScalaObject, AnyRef, Any \\ \hline
\end{tabular}\end{quote} \end{tabular}\end{quote}
Note that \code{D} is inherited twice by \code{F}, once directly, the Note that \code{D} is inherited twice by \code{F}, once directly, the
other time indirectly throgh \code{E}. This is permitted, since other time indirectly through \code{E}. This is permitted, since
\code{D} is a trait. \code{D} is a trait.
@ -1773,9 +1773,9 @@ labeled \code{protected}.
If $M'$ is not an abstract member, then If $M'$ is not an abstract member, then
$M$ must be labeled \code{override}. $M$ must be labeled \code{override}.
\item \item
If $M'$ is labelled \code{abstract} and \code{override}, and $M'$ is a If $M'$ is labeled \code{abstract} and \code{override}, and $M'$ is a
member of the static superclass of the class containing the definition member of the static superclass of the class containing the definition
of $M$, then $M$ must also be labelled \code{abstract} and of $M$, then $M$ must also be labeled \code{abstract} and
\code{override}. \code{override}.
\end{itemize} \end{itemize}
@ -1852,11 +1852,11 @@ definition.
The \code{override} modifier has an additional significance when The \code{override} modifier has an additional significance when
combined with the \code{abstract} modifier. That modifier combination combined with the \code{abstract} modifier. That modifier combination
is only allowed for members of abstract classes. A member is only allowed for members of abstract classes. A member
labelled \code{abstract} and \code{override} must override some labeled \code{abstract} and \code{override} must override some
member of the superclass of the class containing the definition. member of the superclass of the class containing the definition.
We call a member of a template {\em incomplete} if it is either We call a member of a template {\em incomplete} if it is either
abstract (i.e.\ defined by a declaration), or it is labelled abstract (i.e.\ defined by a declaration), or it is labeled
\code{abstract} and \code{override} and it overrides an incomplete \code{abstract} and \code{override} and it overrides an incomplete
member of the template's superclass. member of the template's superclass.
@ -2030,7 +2030,7 @@ This defines a class \code{LinkedList} with an overloaded constructor of type
\begin{lstlisting} \begin{lstlisting}
[a](): LinkedList[a] $\overload$ [a](): LinkedList[a] $\overload$
[a](x: a): LinkedList[a] $\overload$ [a](x: a): LinkedList[a] $\overload$
[a](x: a, xs: LinkList[a]): LinkedList[a] . [a](x: a, xs: LinkedList[a]): LinkedList[a] .
\end{lstlisting} \end{lstlisting}
The second constructor alternative constructs an singleton list, while the The second constructor alternative constructs an singleton list, while the
third one constructs a list with a given head and tail. third one constructs a list with a given head and tail.
@ -3779,7 +3779,7 @@ abstract sealed class Long extends AnyVal {
def coerce: Float // convert to Float def coerce: Float // convert to Float
def + (that: Double): Double; // double addition def + (that: Double): Double; // double addition
def + (that: Float): Double; // float addtion def + (that: Float): Double; // float addition
def + (that: Long): Long = // long addition def + (that: Long): Long = // long addition
/* analogous for -, *, /, % */ /* analogous for -, *, /, % */
@ -3935,7 +3935,7 @@ case class Tuple$n$[+a_1, ..., +a_n](_1: a_1, ..., _$n$: a_$n$) {
} }
\end{lstlisting} \end{lstlisting}
The implicity imported \code{Predef} object (\sref{cls:predef}) defines The implicitly imported \code{Predef} object (\sref{cls:predef}) defines
the names \code{Pair} as an alias of \code{Tuple2} and \code{Triple} the names \code{Pair} as an alias of \code{Tuple2} and \code{Triple}
as an alias for \code{Tuple3}. as an alias for \code{Tuple3}.
@ -3979,7 +3979,7 @@ class PartialFunction[-a,+b] extends Function1[a, b] {
} }
\end{lstlisting} \end{lstlisting}
The implicity imported \code{Predef} object (\sref{cls:predef}) defines the name The implicitly imported \code{Predef} object (\sref{cls:predef}) defines the name
\code{Function} as an alias of \code{Function1}. \code{Function} as an alias of \code{Function1}.
\subsection{Class \large{\code{Array}}}\label{cls:array} \subsection{Class \large{\code{Array}}}\label{cls:array}
@ -4019,7 +4019,7 @@ module Array {
\section{The \large{\code{Predef}} Object}\label{cls:predef} \section{The \large{\code{Predef}} Object}\label{cls:predef}
The \code{Predef} module defines standard functions and type aliases The \code{Predef} module defines standard functions and type aliases
for Scala programs. It is always implicity imported, so that all its for Scala programs. It is always implicitly imported, so that all its
defined members are available without qualification. Here is its defined members are available without qualification. Here is its
definition for the JVM environment. definition for the JVM environment.
@ -4076,504 +4076,3 @@ object Predef {
} }
\end{lstlisting} \end{lstlisting}
\appendix
\chapter{Scala Syntax Summary}
The lexical syntax of Scala is given by the following grammar in EBNF
form.
\begin{lstlisting}
upper ::= `A' | $\ldots$ | `Z' | `$\Dollar$' | `_'
lower ::= `a' | $\ldots$ | `z'
letter ::= upper | lower
digit ::= `0' | $\ldots$ | `9'
special ::= $\mbox{\rm\em ``all other characters except parentheses ([{}]) and periods''}$
op ::= special {special}
varid ::= lower {letter | digit} [`_' [id]]
id ::= upper {letter | digit} [`_' [id]]
| varid
| op
| `\'stringLit
intLit ::= $\mbox{\rm\em ``as in Java''}$
floatLit ::= $\mbox{\rm\em ``as in Java''}$
charLit ::= $\mbox{\rm\em ``as in Java''}$
stringLit ::= $\mbox{\rm\em ``as in Java''}$
symbolLit ::= `\'' id
comment ::= `/*' ``any sequence of characters'' `*/'
| `//' `any sequence of characters up to end of line''
\end{lstlisting}
The context-free syntax of Scala is given by the following EBNF
grammar.
\begin{lstlisting}
Literal ::= intLit
| floatLit
| charLit
| stringLit
| symbolLit
| true
| false
| null
StableId ::= id
| Path `.' id
Path ::= StableId
| [id `.'] this
| [id '.'] super [`[' id `]']`.' id
Type ::= Type1 `=>' Type
| `(' [Types] `)' `=>' Type
| Type1
Type1 ::= SimpleType {with SimpleType} [Refinement]
SimpleType ::= SimpleType TypeArgs
| SimpleType `#' id
| StableId
| Path `.' type
| `(' Type ')'
TypeArgs ::= `[' Types `]'
Types ::= Type {`,' Type}
Refinement ::= `{' [RefineStat {`;' RefineStat}] `}'
RefineStat ::= Dcl
| type TypeDef {`,' TypeDef}
|
Exprs ::= Expr {`,' Expr}
Expr ::= Bindings `=>' Expr
| Expr1
Expr1 ::= if `(' Expr1 `)' Expr [[`;'] else Expr]
| try `{' Block `}' [catch Expr] [finally Expr]
| do Expr [`;'] while `(' Expr ')'
| for `(' Enumerators `)' (do | yield) Expr
| return [Expr]
| throw Expr
| [SimpleExpr `.'] id `=' Expr
| SimpleExpr ArgumentExprs `=' Expr
| PostfixExpr [`:' Type1]
PostfixExpr ::= InfixExpr [id]
InfixExpr ::= PrefixExpr
| InfixExpr id PrefixExpr
PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr
SimpleExpr ::= Literal
| Path
| `(' [Expr] `)'
| BlockExpr
| new Template
| SimpleExpr `.' id
| SimpleExpr TypeArgs
| SimpleExpr ArgumentExprs
ArgumentExprs ::= `(' [Exprs] ')'
| BlockExpr
BlockExpr ::= `{' CaseClause {CaseClause} `}'
| `{' Block `}'
Block ::= {BlockStat `;'} [ResultExpr]
BlockStat ::= Import
| Def
| {LocalModifier} ClsDef
| Expr1
|
ResultExpr ::= Expr1
| Bindings `=>' Block
Enumerators ::= Generator {`;' Enumerator}
Enumerator ::= Generator
| Expr
Generator ::= val Pattern1 `<-' Expr
CaseClause ::= case Pattern [`if' PostfixExpr] `=>' Block
Constr ::= StableId [TypeArgs] [`(' [Exprs] `)']
Pattern ::= Pattern1 { `|' Pattern1 }
Pattern1 ::= varid `:' Type
| `_' `:' Type
| Pattern2
Pattern2 ::= [varid `@'] Pattern3
Pattern3 ::= SimplePattern [ '*' | '?' | '+' ]
| SimplePattern { id SimplePattern }
SimplePattern ::= `_'
| varid
| Literal
| StableId [ `(' [Patterns] `)' ]
| `(' [Patterns] `)'
Patterns ::= Pattern {`,' Pattern}
TypeParamClause ::= `[' TypeParam {`,' TypeParam} `]'
FunTypeParamClause ::= `[' TypeDcl {`,' TypeDcl} `]'
TypeParam ::= [`+' | `-'] TypeDcl
ParamClause ::= `(' [Param {`,' Param}] `)'
Param ::= [def] id `:' Type [`*']
Bindings ::= id [`:' Type1]
| `(' Binding {`,' Binding `)'
Binding ::= id [`:' Type]
Modifier ::= LocalModifier
| private
| protected
| override
LocalModifier ::= abstract
| final
| sealed
Template ::= Constr {`with' Constr} [TemplateBody]
TemplateBody ::= `{' [TemplateStat {`;' TemplateStat}] `}'
TemplateStat ::= Import
| {Modifier} Def
| {Modifier} Dcl
| Expr
|
Import ::= import ImportExpr {`,' ImportExpr}
ImportExpr ::= StableId `.' (id | `_' | ImportSelectors)
ImportSelectors ::= `{' {ImportSelector `,'}
(ImportSelector | `_') `}'
ImportSelector ::= id [`=>' id | `=>' `_']
Dcl ::= val ValDcl {`,' ValDcl}
| var VarDcl {`,' VarDcl}
| def FunDcl {`,' FunDcl}
| type TypeDcl {`,' TypeDcl}
ValDcl ::= id `:' Type
VarDcl ::= id `:' Type
FunDcl ::= id [FunTypeParamClause] {ParamClause} `:' Type
TypeDcl ::= id [`>:' Type] [`<:' Type]
Def ::= val PatDef {`,' PatDef}
| var VarDef {`,' VarDef}
| def FunDef {`,' FunDef}
| type TypeDef {`,' TypeDef}
| ClsDef
PatDef ::= Pattern `=' Expr
VarDef ::= id [`:' Type] `=' Expr
| id `:' Type `=' `_'
FunDef ::= id [FunTypeParamClause] {ParamClause}
[`:' Type] `=' Expr
| this ParamClause `=' ConstrExpr
TypeDef ::= id [TypeParamClause] `=' Type
ClsDef ::= ([case] class | trait) ClassDef {`,' ClassDef}
| [case] object ObjectDef {`,' ObjectDef}
ClassDef ::= id [TypeParamClause] [ParamClause]
[`:' SimpleType] ClassTemplate
ObjectDef ::= id [`:' SimpleType] ClassTemplate
ClassTemplate ::= extends Template
| TemplateBody
|
ConstrExpr ::= this ArgumentExprs
| `{' this ArgumentExprs {`;' BlockStat} `}'
CompilationUnit ::= [package QualId `;'] {TopStat `;'} TopStat
TopStat ::= {Modifier} ClsDef
| Import
| Packaging
|
Packaging ::= package QualId `{' {TopStat `;'} TopStat `}'
QualId ::= id {`.' id}
\end{lstlisting}
\chapter{Implementation Status}
The present Scala compiler does not yet implement all of the Scala
specification. Its currently existing omissions and deviations are
listed below. We are working on a refined implementation that
addresses these issues.
\begin{enumerate}
\item
Unicode support is still limited. At present we only permit Unicode
encodings \verb@\uXXXX@ in strings and backquote-enclosed identifiers.
To define or access a Unicode identifier, you need to put it in
backquotes and use the \verb@\uXXXX@ encoding.
\item
The unicode operator ``$\Rightarrow$''
(\sref{sec:idents}) is not yet recognized; you need to use the two
character ASCII equivalent ``\code{=>}'' instead.
\item
The current implementation does not yet support run-time types.
All types are erased (\sref{sec:erasure}) during compilation. This means that
the following operations give potentially wrong results.
\begin{itemize}
\item
Type tests and type casts to parameterized types. Here it is only tested
that a value is an instance of the given top-level type constructor.
\item
Type tests and type casts to type parameters and abstract types. Here
it is only tested that a value is an instance of the type parameter's upper bound.
\item
Polymorphic array creation. If \code{t} is a type variable or abstract type, then
\code{new Array[t]} will yield an array of the upper bound of \code{t}.
\end{itemize}
\item
Return expressions are not yet permitted inside an anonymous function
or inside a call-by-name argument (i.e.\ a function argument corresponding to a
\code{def} parameter).
\item
Members of the empty package (\sref{sec:packagings}) cannot yet be
accessed from other source files. Hence, all library classes and
objects have to be in some package.
\item
At present, auxiliary constructors (\sref{sec:constr-defs}) are only permitted
for monomorphic classes.
\item
The \code{Array} class supports as yet only a restricted set of
operations as given in \sref{cls:array}. It is planned to extend that
interface. In particular, arrays will implement the \code{scala.Seq}
trait as well as the methods needed to support for-comprehensions.
\item
At present, all classes used as mixins must be accessible to the Scala
compiler in source form.
\end{enumerate}
\end{document}
\comment{
\section{Definitions}
For a possibly recursive definition such as $\LET;x_1 = e_1
;\ldots; \LET x_n = e_n$, local type inference proceeds as
follows.
A first phase assigns {\em a-priori types} to the $x_i$. The a-priori
type of $x$ is the declared type of $x$ if a declared type is
given. Otherwise, it is the inherited type, if one is
given. Otherwise, it is undefined.
A second phase assigns completely defined types to the $x_i$, in some
order. The type of $x$ is the a-priori type, if it is completely
defined. Otherwise, it is the a-priori type of $x$'s right hand side.
The a-priori type of an expression $e$ depends on the form of $e$.
\begin{enumerate}
\item
The a-priori type of a
typed expression $e:T$ is $T$.
\item
The a-priori type of a class instance
creation expression $c;\WITH;(b)$ is $C;\WITH;R$ where $C$ is the
type of the class given in $c$ and $R$ is the a-priori type of block
$b$.
\item
The a-priori type of a block is a record consisting the a-priori
types of each non-private identifier which is declared in the block
and which is visible at in last statement of the block. Here, it is
required that every import clause $\IMPORT;e_1 \commadots e_n$ refers
to expressions whose type can be computed with the type information
determined so far. Otherwise, a compile time error results.
\item
The a-priori type of any other expression is the expression's type, if
that type can be computed with the type information determined so far.
Otherwise, a compile time error results.
\end{enumerate}
The compiler will find an ordering in which types are assigned without
compiler errors to all variables $x_1 \commadots x_n$, if such an
ordering exists. This can be achieved by lazy evaluation.
}
\section{Exceptions}
\label{sec:exceptions}
There is a predefined type \code{Throwable}, as well as functions to
throw and handle values of type \code{Throwable}. These are declared
as follows.
\begin{lstlisting}
class Throwable {
def throw[a]: a
}
class ExceptOrFinally[a] {
def except (handler: PartialFunction[Throwable,a]): a
def finally (def handler: Unit): a
}
def try [a] (def body: a): ExceptOrFinally[a]
\end{lstlisting}
The type \code{Throwable} represents exceptions and error objects; it
may be identified with an analogous type of the underlying
implementation such as \code{java.lang.Throwable}. We will in the
following loosely call values of type \code{Throwable} exceptions.
The \code{throw} method in \code{Throwable} aborts execution of the
thread executing it and passes the thrown exception to the handler
that was most recently installed by a
\code{try} function in the current thread. If no \code{try} method is
active, the thread terminates.
The \code{try} function executes its body with the given exception
handler. A \code{try} expression comes in two forms. The first form is
\begin{lstlisting}
try $body$ except $handler$ .
\end{lstlisting}
If $body$ executes without an exception being thrown, then executing
the try expression is equivalent to just executing $body$. If some
exception is thrown from within $body$ for which \code{handler} is defined,
the handler is invoked with the thrown exception as argument.
The second form of a try expression is
\begin{lstlisting}
try $body$ finally $handler$ .
\end{lstlisting}
This expression will execute $body$. A normal execution of $body$ is
followed by an invocation of the $handler$ expression. The $handler$
expression does not take arguments and has \code{Unit} as result type.
If execution of the handler expression throws an exception, this
exception is propagated out of the \code{try} statement. Otherwise,
if an exception was thrown in $body$ prior to invocation of $handler$,
that exception is re-thrown after the invocation. Finally, if both
$body$ and $handler$ terminate normally, the original result of
$body$ is the result of the \code{try} expression.
\example An example of a try-except expression:
\begin{lstlisting}
try {
System.in.readString()
} except {
case ex: EndOfFile => ""
}
\end{lstlisting}
\example An example of a try-finally expression:
\begin{lstlisting}
file = open (fileName)
if (file != null) {
try {
process (file)
} finally {
file.close
}
}
\end{lstlisting}
\section{Concurrency}
\label{sec:concurrency}
\subsection{Basic Concurrency Constructs}
Scala programs may be executed by several threads that operate
concurrently. The thread model used is based on the model of the
underlying run-time system. We postulate a predefined
class \code{Thread} for run-time threads,
\code{fork} function to spawn off a new thread,
as well as \code{Monitor} and \code{Signal} classes. These are
specified as follows\notyet{Concurrency constructs are}.
\begin{lstlisting}
class Thread { $\ldots$ }
def fork (def p: Unit): Thread
\end{lstlisting}
The \code{fork} function runs its argument computation \code{p} in a
separate thread. It returns the thread object immediately to its
caller. Unhandled exceptions (\sref{sec:exceptions}) thrown during
evaluation of \code{p} abort execution of the forked thread and are
otherwise ignored.
\begin{lstlisting}
class Monitor {
def synchronized [a] (def e: a): a
}
\end{lstlisting}
Monitors define a \code{synchronized} method which provides mutual
exclusion between threads. It executes its argument computation
\code{e} while asserting exclusive ownership of the monitor
object whose method is invoked. If some other thread has ownership of
the same monitor object, the computation is delayed until the other
process has relinquished its ownership. Ownership of a monitor is
relinquished at the end of the argument computation, and while the
computation is waiting for a signal.
\begin{lstlisting}
class Signal {
def wait: Unit
def wait(msec: Long): Unit
def notify: Unit
def notifyAll: Unit
}
\end{lstlisting}
The \code{Signal} class provides the basic means for process
synchronization. The \code{wait} method of a signal suspends the
calling thread until it is woken up by some future invocation of the
signal's \code{notify} or \code{notifyAll} method. The \code{notify}
method wakes up one thread that is waiting for the signal. The
\code{notifyAll} method wakes up all threads that are waiting for the
signal. A second version of the \code{wait} method takes a time-out
parameter (given in milliseconds). A thread calling \code{wait(msec)}
will suspend until unblocked by a \code{notify} or \code{notifyAll}
method, or until the \code{msec} millseconds have passed.
\subsection{Channels}
\begin{lstlisting}
class Channel[a] {
def write(x: a): Unit
def read: a
}
\end{lstlisting}
An object of type \code{Channel[a]} Channels offer a write-operation
which writes data of type \code{a} to the channel, and a read
operation, which returns written data as a result. The write operation
is non-blocking; that is it returns immediately without waiting for
the written data to be read.
\subsection{Message Spaces}
The Scala library also provides message spaces as a higher-level,
flexible construct for process synchronization and communication. A
{\em message} is an arbitrary object that inherits from the
\code{Message} class.
There is a special message \code{TIMEOUT} which is used to signal a time-out.
\begin{lstlisting}
class Message
case class TIMEOUT extends Message
\end{lstlisting}
Message spaces implement the following class.
\begin{lstlisting}
class MessageSpace {
def send(msg: Message): Unit
def receive[a](f: PartialFunction1[Message, a]): a
def receiveWithin[a](msec: Long)(f: PartialFunction1[Message, a]): a
}
\end{lstlisting}
The state of a message space consists of a multi-set of messages.
Messages are added to the space using the \code{send} method. Messages
are removed using the \code{receive} method, which is passed a message
processor \code{f} as argument, which is a partial function from
messages to some arbitrary result type. Typically, this function is
implemented as a pattern matching expression. The \code{receive}
method blocks until there is a message in the space for which its
message processor is defined. The matching message is then removed
from the space and the blocked thread is restarted by applying the
message processor to the message. Both sent messages and receivers are
ordered in time. A receiver $r$ is applied to a matching message $m$
only if there is no other (message, receiver) pair which precedes $(m,
r)$ in the partial ordering on pairs that orders each component in
time.
The message space class also offers a method \code{receiveWithin}
which blocks for only a specified maximal amount of time. If no
message is received within the specified time interval (given in
milliseconds), the message processor argument $f$ will be unblocked
with the special \code{TIMEOUT} message.
case class extends { $\ldots$ }
trait List { }
class Nil
class Cons
\comment{changes:
Type ::= SimpleType {with SimpleType} [with Refinement]
| class SimpleType
SimpleType ::= SimpleType [TypeArgs]
| `(' [Types] `)'
|
| this
}

View File

@ -22,7 +22,5 @@ Martin Odersky
\input{RationalePart} \input{RationalePart}
\bibliographystyle{alpha}
\bibliography{Scala}
\end{document} \end{document}

View File

@ -93,9 +93,12 @@ Matthias Zenger \\[25mm]\ }
\input{RationalePart} \input{RationalePart}
\part{The Scala Language Specification} \part{The Scala Language Specification}
\input{ReferencePart} \input{ReferencePart}
\bibliographystyle{alpha} \bibliographystyle{alpha}
\bibliography{Scala} \bibliography{Scala}
\input{ReferencePartAppendix}
\end{document} \end{document}

View File

@ -96,6 +96,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
} }
def lateEnter(unit: Unit, sym: Symbol): unit = { def lateEnter(unit: Unit, sym: Symbol): unit = {
//System.out.println("late enter: " + sym + " " + sym.isModule());//DEBUG
enterUnit(unit); enterUnit(unit);
if (sym.rawFirstInfo().isInstanceOf[SourceCompleter]) { if (sym.rawFirstInfo().isInstanceOf[SourceCompleter]) {
sym.setInfo(Type.ErrorType); sym.setInfo(Type.ErrorType);

View File

@ -2,14 +2,14 @@ bug95.scala:1: illegal inheritance from sealed class
class C extends AnyVal; class C extends AnyVal;
^ ^
bug95.scala:1: illegal inheritance; bug95.scala:1: illegal inheritance;
scala.AnyVal does not conform to scala.ScalaObject's supertype scala.AnyVal does not conform to scala.ScalaObject's supertype java.lang.Object
class C extends AnyVal; class C extends AnyVal;
^ ^
bug95.scala:2: illegal inheritance from sealed class bug95.scala:2: illegal inheritance from sealed class
class T extends Unit; class T extends Unit;
^ ^
bug95.scala:2: illegal inheritance; bug95.scala:2: illegal inheritance;
scala.Unit does not conform to scala.ScalaObject's supertype scala.Unit does not conform to scala.ScalaObject's supertype java.lang.Object
class T extends Unit; class T extends Unit;
^ ^
four errors found four errors found