*** 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:
parent
cf69c6449c
commit
bcfd151a69
|
@ -23,8 +23,8 @@ interesting programming techniques. The present informal exposition is
|
|||
meant to be complemented by the Java Language Reference Manual which
|
||||
specifies Scala in a more detailed and precise way.
|
||||
|
||||
\paragraph{Acknowledgement}
|
||||
We owe a great dept to Sussman and Abelson's wonderful book
|
||||
\paragraph{Acknowledgment}
|
||||
We owe a great debt to Abelson's and Sussman's wonderful book
|
||||
``Structure and Interpretation of Computer
|
||||
Programs''\cite{abelson-sussman:structure}. Many of their examples and
|
||||
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.
|
||||
\end{itemize}
|
||||
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
|
||||
because it is one of the things that makes it easy to combine Scala
|
||||
components with components written in mainstream languages such as
|
||||
|
@ -106,7 +106,7 @@ def sort(xs: List[int]): List[int] = {
|
|||
\end{lstlisting}
|
||||
|
||||
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
|
||||
\code{filter} and \code{:::}.}
|
||||
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 Partition the lists into two sub-lists containing elements that
|
||||
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
|
||||
the sort function.\footnote{This is not quite what the imperative algorithm does;
|
||||
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}
|
||||
The process behavior is defined by its \code{run} method. That method
|
||||
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
|
||||
determined by the \code{timeToShutdown} constant and replies to
|
||||
further offers that the auction is closed.
|
||||
|
@ -632,7 +632,7 @@ def sqrtIter(guess: double, x: double): double =
|
|||
else sqrtIter(improve(guess, x), x);
|
||||
\end{lstlisting}
|
||||
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.
|
||||
|
||||
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;
|
||||
\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}.
|
||||
\begin{lstlisting}
|
||||
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
|
||||
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
|
||||
is not tail-recursive; it needs space proportional to its input
|
||||
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,
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -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
|
||||
outside class \code{Rational}. They are used in the implementation of
|
||||
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.
|
||||
|
||||
\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
|
||||
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
|
||||
return true if the set \code{s} contains the element \code{x}, and
|
||||
should return \code{false} otherwise. The interface of such sets is
|
||||
|
@ -1750,7 +1750,7 @@ trait Nat {
|
|||
def - (that: Nat): Nat;
|
||||
}
|
||||
\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{N} is represented as \code{N} applications of the \code{Succ}
|
||||
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))
|
||||
\end{lstlisting}
|
||||
\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
|
||||
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
|
||||
|
@ -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
|
||||
address, which is what the as the default implementation of \code{hashCode} does.
|
||||
\item
|
||||
Case classes implicity come with nullary accessor methods which
|
||||
Case classes implicitly come with nullary accessor methods which
|
||||
retrieve the constructor arguments.
|
||||
In our example, \code{Number} would obtain an accessor method
|
||||
\begin{lstlisting}
|
||||
|
@ -2418,7 +2418,7 @@ val s = new EmptySet[java.io.File]
|
|||
$\mbox{\sl parameter bound}$ Ord[java.io.File].
|
||||
\end{lstlisting}
|
||||
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}
|
||||
package scala;
|
||||
trait Ord[t <: Ord[t]]: t {
|
||||
|
@ -2519,7 +2519,7 @@ class Array[+a] {
|
|||
$\mbox{\sl appears in contravariant position.}$
|
||||
}
|
||||
\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}
|
||||
potentially changes state, and therefore undermines the soundness of
|
||||
co-variant subtyping.
|
||||
|
@ -2580,7 +2580,7 @@ often suggest a useful generalization of the contested method.
|
|||
\section{Least Types}
|
||||
|
||||
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
|
||||
do. For co-variant stacks, however, one can use the following idiom:
|
||||
\begin{lstlisting}
|
||||
|
@ -2677,14 +2677,14 @@ follows.
|
|||
\begin{lstlisting}
|
||||
def divmod(x: int, y: int) = Pair(x / y, x % y)
|
||||
\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
|
||||
using the names of the constructor parameters \lstinline@_$i$@, as in the following example:
|
||||
\begin{lstlisting}
|
||||
val xy = divmod(x, y);
|
||||
System.out.println("quotient: " + x._1 + ", rest: " + x._2);
|
||||
\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}
|
||||
divmod(x, y) match {
|
||||
case Pair(n, d) =>
|
||||
|
@ -3153,7 +3153,7 @@ computation over lists, like:
|
|||
\item extracting from a list all elements satisfying a criterion.
|
||||
\item combine the elements of a list using some operator.
|
||||
\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. We now discuss a set of commonly used higher-order
|
||||
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)
|
||||
}
|
||||
\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}
|
||||
def scaleList(xs: List[double], factor: double) =
|
||||
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)
|
||||
}
|
||||
\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.
|
||||
\begin{lstlisting}
|
||||
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
|
||||
divided without remainder only by one and itself. The most direct
|
||||
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
|
||||
\code{List.range} which is defined in object \code{List} as follows.
|
||||
\begin{lstlisting}
|
||||
|
@ -3270,7 +3270,7 @@ object List { ...
|
|||
if (from >= end) Nil else from :: range(from + 1, end);
|
||||
\end{lstlisting}
|
||||
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.
|
||||
\begin{lstlisting}
|
||||
def isPrime(n: int) =
|
||||
|
@ -3301,7 +3301,7 @@ def product(xs: List[int]): int = xs match {
|
|||
case y :: ys => y * product(ys)
|
||||
}
|
||||
\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
|
||||
inserts a given binary operator between adjacent elements of a given list.
|
||||
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
|
||||
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.
|
||||
This notation builds a bridge between set-comprehensions in
|
||||
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
|
||||
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
|
||||
column, row, or diagional). We will now develop a solution to this
|
||||
problem, generalizing it to chessboards of arbitrary size. Hence, the
|
||||
problem is to place $n$ queens on a chessboard of size $n \times n$.
|
||||
column, row, or diagonal). We will now develop a solution to this
|
||||
problem, generalizing it to chess-boards of arbitrary size. Hence, the
|
||||
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.
|
||||
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
|
||||
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
|
||||
|
@ -4006,7 +4006,7 @@ element for each solution.
|
|||
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 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:
|
||||
\begin{lstlisting}
|
||||
def queens(n: int): List[List[int]] = {
|
||||
|
@ -4041,7 +4041,7 @@ Here is a small example database:
|
|||
\begin{lstlisting}
|
||||
val books: List[Book] = List(
|
||||
Book("Structure and Interpretation of Computer Programs",
|
||||
List("Abelson, Harald", "Sussman, Gerald J.")),
|
||||
List("Abelson, Harold", "Sussman, Gerald J.")),
|
||||
Book("Principles of Compiler Design",
|
||||
List("Aho, Alfred", "Ullman, Jeffrey")),
|
||||
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
|
||||
not needed but we would still like the flexibility of generators and
|
||||
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}
|
||||
for ( $s$ ) $e$
|
||||
\end{lstlisting}
|
||||
|
@ -4270,7 +4270,7 @@ theory underlying functional programming.
|
|||
|
||||
In this chapter, we introduce functions with side effects and study
|
||||
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.
|
||||
|
||||
\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
|
||||
{\em not} regarded as a variable definition, because the initializer
|
||||
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
|
||||
methods with a piece of state.}. If one does not know, or does not
|
||||
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
|
||||
case (first @ Pair(time, act)) :: ag1 =>
|
||||
if (actiontime < time) Pair(actiontime, action) :: ag
|
||||
else first :: insert(ag1)
|
||||
else first :: insert(ag1)
|
||||
}
|
||||
agenda = insert(agenda)
|
||||
}
|
||||
|
@ -4801,7 +4801,7 @@ sum 15 new_value = false
|
|||
\section{Summary}
|
||||
|
||||
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
|
||||
computation. In particular, referential transparency is lost. On the
|
||||
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
|
||||
stateful objects. We have seen how real-world objects that change
|
||||
with time can be modelled by changing the state of variables in a
|
||||
computation. Time changes in the real world thus are modelled by time
|
||||
with time can be modeled by changing the state of variables in a
|
||||
computation. Time changes in the real world thus are modeled by time
|
||||
changes in program execution. Of course, such time changes are usually
|
||||
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
|
||||
|
@ -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
|
||||
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
|
||||
done in computation. Instead of overwriting a variable with successive
|
||||
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.
|
||||
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)
|
||||
rest \code{xs}. Instead of \code{xs ::: ys}, one uses the operation
|
||||
\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 describe potentially infinite lists. However, there is no
|
||||
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}
|
||||
trait Iterator[+a] {
|
||||
def hasNext: boolean;
|
||||
|
@ -5035,7 +5035,7 @@ returns all elements of the original iterator that satisfy a criterion
|
|||
\end{lstlisting}
|
||||
In fact, \code{filter} returns instances of a subclass of iterators
|
||||
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
|
||||
\code{head}, but does not advance beyond that element. Hence, the
|
||||
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]();
|
||||
openJobs.write{
|
||||
new Job {
|
||||
type t = a;
|
||||
def task = p;
|
||||
def ret(x: a) = reply.set(x);
|
||||
type t = a;
|
||||
def task = p;
|
||||
def ret(x: a) = reply.set(x);
|
||||
}
|
||||
}
|
||||
() => reply.get
|
||||
|
@ -6604,7 +6604,7 @@ As a simple example of how mailboxes are used, consider a
|
|||
one-place buffer:
|
||||
\begin{lstlisting}
|
||||
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
|
||||
m send Empty; // Initialization
|
||||
def write(x: int): unit =
|
||||
|
@ -6662,10 +6662,10 @@ Otherwise, the message is appended to the linked list of sent messages.
|
|||
if (s1 != null) {
|
||||
s.next = s1.next; s1.elem
|
||||
} else {
|
||||
val r = insert(lastReceiver, new Receiver {
|
||||
val r = insert(lastReceiver, new Receiver {
|
||||
def isDefined(msg: Any) = f.isDefinedAt(msg);
|
||||
});
|
||||
lastReceiver = r;
|
||||
lastReceiver = r;
|
||||
r.elem.wait();
|
||||
r.elem.msg
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ varid ::= lower {letter $|$ digit} [`_' [id]]
|
|||
id ::= upper {letter $|$ digit} [`_' [id]]
|
||||
| varid
|
||||
| op
|
||||
| ```string chars`''
|
||||
| ```string chars`''
|
||||
\end{lstlisting}
|
||||
|
||||
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
|
||||
with a special character followed by an arbitrary sequence of special
|
||||
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
|
||||
match rule applies. For instance, the string
|
||||
|
||||
|
@ -423,7 +423,7 @@ contravariant in their argument types.
|
|||
\label{sec:synthetic-types}
|
||||
|
||||
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.
|
||||
|
||||
\subsection{Method Types}
|
||||
|
@ -693,7 +693,7 @@ transitive relation that satisfies the following conditions.
|
|||
one has $\mbox{\code{scala.AllRef}} \conforms T$.
|
||||
\item A type variable or abstract type $t$ conforms to its upper bound and
|
||||
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
|
||||
$T$ conforms to $U$.
|
||||
\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
|
||||
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
|
||||
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
|
||||
which has a type specified as a least upper or greatest lower bound,
|
||||
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
|
||||
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@.
|
||||
|
||||
|
||||
|
@ -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
|
||||
$s_i$ and $s_j$ must be an import clause,
|
||||
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{
|
||||
Every basic definition may introduce several defined names, separated
|
||||
|
@ -914,7 +914,7 @@ the type definition
|
|||
\comment{
|
||||
If an element in such a sequence introduces only the defined name,
|
||||
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
|
||||
more than just a defined name and parameters. Examples:
|
||||
\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$@~
|
||||
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
|
||||
\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
|
||||
is converted to a function type instead of being applied immediately,
|
||||
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 following table:
|
||||
\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 \\
|
||||
B & B & B, 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
|
||||
\end{tabular}\end{quote}
|
||||
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.
|
||||
|
||||
|
||||
|
@ -1773,9 +1773,9 @@ labeled \code{protected}.
|
|||
If $M'$ is not an abstract member, then
|
||||
$M$ must be labeled \code{override}.
|
||||
\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
|
||||
of $M$, then $M$ must also be labelled \code{abstract} and
|
||||
of $M$, then $M$ must also be labeled \code{abstract} and
|
||||
\code{override}.
|
||||
\end{itemize}
|
||||
|
||||
|
@ -1852,11 +1852,11 @@ definition.
|
|||
The \code{override} modifier has an additional significance when
|
||||
combined with the \code{abstract} modifier. That modifier combination
|
||||
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.
|
||||
|
||||
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
|
||||
member of the template's superclass.
|
||||
|
||||
|
@ -2030,7 +2030,7 @@ This defines a class \code{LinkedList} with an overloaded constructor of type
|
|||
\begin{lstlisting}
|
||||
[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}
|
||||
The second constructor alternative constructs an singleton list, while the
|
||||
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 + (that: Double): Double; // double addition
|
||||
def + (that: Float): Double; // float addtion
|
||||
def + (that: Float): Double; // float addition
|
||||
def + (that: Long): Long = // long addition
|
||||
/* analogous for -, *, /, % */
|
||||
|
||||
|
@ -3935,7 +3935,7 @@ case class Tuple$n$[+a_1, ..., +a_n](_1: a_1, ..., _$n$: a_$n$) {
|
|||
}
|
||||
\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}
|
||||
as an alias for \code{Tuple3}.
|
||||
|
||||
|
@ -3979,7 +3979,7 @@ class PartialFunction[-a,+b] extends Function1[a, b] {
|
|||
}
|
||||
\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}.
|
||||
|
||||
\subsection{Class \large{\code{Array}}}\label{cls:array}
|
||||
|
@ -4019,7 +4019,7 @@ module Array {
|
|||
\section{The \large{\code{Predef}} Object}\label{cls:predef}
|
||||
|
||||
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
|
||||
definition for the JVM environment.
|
||||
|
||||
|
@ -4076,504 +4076,3 @@ object Predef {
|
|||
}
|
||||
\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
|
||||
}
|
||||
|
|
|
@ -22,7 +22,5 @@ Martin Odersky
|
|||
|
||||
\input{RationalePart}
|
||||
|
||||
\bibliographystyle{alpha}
|
||||
\bibliography{Scala}
|
||||
|
||||
\end{document}
|
|
@ -93,9 +93,12 @@ Matthias Zenger \\[25mm]\ }
|
|||
\input{RationalePart}
|
||||
|
||||
\part{The Scala Language Specification}
|
||||
|
||||
\input{ReferencePart}
|
||||
|
||||
\bibliographystyle{alpha}
|
||||
\bibliography{Scala}
|
||||
|
||||
\input{ReferencePartAppendix}
|
||||
|
||||
\end{document}
|
||||
|
|
|
@ -96,6 +96,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
|
|||
}
|
||||
|
||||
def lateEnter(unit: Unit, sym: Symbol): unit = {
|
||||
//System.out.println("late enter: " + sym + " " + sym.isModule());//DEBUG
|
||||
enterUnit(unit);
|
||||
if (sym.rawFirstInfo().isInstanceOf[SourceCompleter]) {
|
||||
sym.setInfo(Type.ErrorType);
|
||||
|
|
|
@ -2,14 +2,14 @@ bug95.scala:1: illegal inheritance from sealed class
|
|||
class C extends AnyVal;
|
||||
^
|
||||
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;
|
||||
^
|
||||
bug95.scala:2: illegal inheritance from sealed class
|
||||
class T extends Unit;
|
||||
^
|
||||
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;
|
||||
^
|
||||
four errors found
|
||||
|
|
Loading…
Reference in New Issue