From 8a94b49aab6f7802b80f65592c27189377607cc0 Mon Sep 17 00:00:00 2001 From: schinz Date: Fri, 22 Aug 2003 08:42:57 +0000 Subject: - removed obsolete files (which were renamed) --- doc/reference/examples.bib | 20 - doc/reference/examples.verb.tex | 5494 ------------------------------ doc/reference/rationale-chapter.verb.tex | 125 - doc/reference/rationale.verb.tex | 21 - doc/reference/reference.verb.tex | 5025 --------------------------- 5 files changed, 10685 deletions(-) delete mode 100644 doc/reference/examples.bib delete mode 100644 doc/reference/examples.verb.tex delete mode 100644 doc/reference/rationale-chapter.verb.tex delete mode 100644 doc/reference/rationale.verb.tex delete mode 100644 doc/reference/reference.verb.tex (limited to 'doc') diff --git a/doc/reference/examples.bib b/doc/reference/examples.bib deleted file mode 100644 index a0bbd57115..0000000000 --- a/doc/reference/examples.bib +++ /dev/null @@ -1,20 +0,0 @@ - -@Book{ abelson-sussman:structure, - author = {Harold Abelson and Gerald Jay Sussman and Julie Sussman}, - title = {The Structure and Interpretation of Computer Programs, 2nd - edition}, - year = {1996}, - publisher = {MIT Press}, - address = {Cambridge, Massachusetts} -} - -@InProceedings{ odersky-et-al:fool10, - author = {Martin Odersky and Vincent Cremet and Christine R\"ockl - and Matthias Zenger}, - title = {A Nominal Theory of Objects with Dependent Types}, - booktitle = {Proc. FOOL 10}, - year = 2003, - month = jan, - note = {\verb@http://www.cis.upenn.edu/~bcpierce/FOOL/FOOL10.html@} - -} diff --git a/doc/reference/examples.verb.tex b/doc/reference/examples.verb.tex deleted file mode 100644 index 24bcb5c363..0000000000 --- a/doc/reference/examples.verb.tex +++ /dev/null @@ -1,5494 +0,0 @@ -%% $Id$ - -\documentclass[11pt]{book} - -\usepackage{fleqn,a4wide,vquote,modefs,math,prooftree,scaladefs} -\newcommand{\exercise}{\paragraph{Exercise:}} -\newcommand{\rewriteby}[1]{\mbox{\tab\tab\rm(#1)}} - -\title{Scala By Examples} - -\author{ -Martin Odersky \\ LAMP/EPFL -} - -\sloppy -\begin{document} -\maketitle -\bibliographystyle{alpha} - -\chapter{\label{chap:intro}Introduction} - -\input{rationale-chapter.tex} - -The rest of this document is structured as -follows. Chapters~\ref{chap:example-one} and -\ref{chap:example-auction} highlight some of the features that make -Scala interesting. The following chapters introduce the language -constructs of Scala in a more thorough -way. Chapter~\ref{chap:simple-funs} introduces basic expressions and -simple functions. Chapter~\ref{chap:first-class-funs} introduces -higher-order functions. (to be continued). - -This document ows a great dept to Sussman and Abelson'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 -in each case been changed from Scheme to Scala. Furthermore, the -examples make use of Scala's object-oriented constructs where -appropriate. - - -\chapter{\label{chap:example-one}A First Example} - -As a first example, here is an implementation of Quicksort in Scala. -\begin{verbatim} -def sort(xs: Array[int]): unit = { - - def swap(i: int, j: int): unit = { - val t = xs(i); xs(i) = xs(j); xs(j) = t; - } - - def sort1(l: int, r: int): unit = { - val pivot = xs((l + r) / 2); - var i = l, j = r; - while (i <= j) { - while (xs(i) < pivot) { i = i + 1 } - while (xs(j) > pivot) { j = j - 1 } - if (i <= j) { - swap(i, j); - i = i + 1; - j = j - 1; - } - } - if (l < j) sort1(l, j); - if (j < r) sort1(i, r); - } - - sort1(0, xs.length - 1); -} -\end{verbatim} -The implementation looks quite similar to what one would write in Java -or C. We use the same operators and similar control structures. -There are also some minor syntactical differences. In particular: -\begin{itemize} -\item -Definitions start with a reserved word. Function definitions start -with \verb@def@, variable definitions start with \verb@var@ and -definitions of values (i.e. read only variables) start with \verb@val@. -\item -The declared type of a symbol is given after the symbol and a colon. -The declared type can often be omitted, because the compiler can infer -it from the context. -\item -We use \verb@unit@ instead of \verb@void@ to define the result type of -a procedure. -\item -Array types are written \verb@Array[T]@ rather than \verb@T[]@, -and array selections are written \verb@a(i)@ rather than \verb@a[i]@. -\item -Functions can be nested inside other functions. Nested functions can -access parameters and local variables of enclosing functions. For -instance, the name of the array \verb@a@ is visible in functions -\verb@swap@ and \verb@sort1@, and therefore need not be passed as a -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 -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 -Java, C\# or Visual Basic. - -However, it is also possible to write programs in a style which looks -completely different. Here is Quicksort again, this time written in -functional style. - -\begin{verbatim} -def sort(xs: List[int]): List[int] = { - val pivot = a(a.length / 2); - sort(a.filter(x => x < pivot)) - ::: a.filter(x => x == pivot) - ::: sort(a.filter(x => x > pivot)) -} -\end{verbatim} - -The functional program works with lists instead of arrays.\footnote{In -a future complete implemenetation of Scala, we could also have used arrays -instead of lists, but at the moment arrays do not yet support -\verb@filter@ and \verb@:::@.} -It captures the essence of the quicksort algorithm in a concise way: -\begin{itemize} -\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. -\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 -less than or greater or equal to pivot.} -\item The result is obtained by appending the three sub-lists together. -\end{itemize} -Both the imperative and the functional implementation have the same -asymptotic complexity -- $O(N;log(N))$ in the average case and -$O(N^2)$ in the worst case. But where the imperative implementation -operates in place by modifying the argument array, the functional -implementation returns a new sorted list and leaves the argument -list unchanged. The functional implementation thus requires more -transient memory than the imperative one. - -The functional implementation makes it look like Scala is a language -that's specialized for functional operations on lists. In fact, it -is not; all of the operations used in the example are simple library -methods of a class \verb@List[t]@ which is part of the standard -Scala library, and which itself is implemented in Scala. - -In particular, there is the method \verb@filter@ which takes as -argument a {\em predicate function} that maps list elements to -boolean values. The result of \verb@filter@ is a list consisting of -all the elements of the original list for which the given predicate -function is true. The \verb@filter@ method of an object of type -\verb@List[t]@ thus has the signature -\begin{verbatim} - def filter(p: t => boolean): List[t] . -\end{verbatim} -Here, \verb@t => boolean@ is the type of functions that take an element -of type \verb@t@ and return a \verb@boolean@. Functions like -\verb@filter@ that take another function as argument or return one as -result are called {\em higher-order} functions. - -In the quicksort program, \verb@filter@ is applied three times to an -anonymous function argument. The first argument, -\verb@x => x <= pivot@ represents the function that maps its parameter -\verb@x@ to the boolean value \verb@x <= pivot@. That is, it yields -true if \verb@x@ is smaller or equal than \verb@pivot@, false -otherwise. The function is anonymous, i.e.\ it is not defined with a -name. The type of the \verb@x@ parameter is omitted because a Scala -compiler can infer it automatically from the context where the -function is used. To summarize, \verb@xs.filter(x => x <= pivot)@ -returns a list consisting of all elements of the list \verb@xs@ that are -smaller than \verb@pivot@. - -\comment{ -It is also possible to apply higher-order functions such as -\verb@filter@ to named function arguments. Here is functional -quicksort again, where the two anonymous functions are replaced by -named auxiliary functions that compare the argument to the -\verb@pivot@ value. - -\begin{verbatim} -def sort (xs: List[int]): List[int] = { - val pivot = xs(xs.length / 2); - def leqPivot(x: int) = x <= pivot; - def gtPivot(x: int) = x > pivot; - def eqPivot(x: int) = x == pivot; - sort(xs filter leqPivot) - ::: sort(xs filter eqPivot) - ::: sort(xs filter gtPivot) -} -\end{verbatim} -} - -An object of type \verb@List[t]@ also has a method ``\verb@:::@'' -which takes an another list and which returns the result of appending this -list to itself. This method has the signature -\begin{verbatim} - def :::(that: List[t]): List[t] . -\end{verbatim} -Scala does not distinguish between identifiers and operator names. An -identifier can be either a sequence of letters and digits which begins -with a letter, or it can be a sequence of special characters, such as -``\verb@+@'', ``\verb@*@'', or ``\verb@:@''. The last definition thus -introduced a new method identifier ``\verb@:::@''. This identifier is -used in the Quicksort example as a binary infix operator that connects -the two sub-lists resulting from the partition. In fact, any method -can be used as an operator in Scala. The binary operation $E;op;E'$ -is always interpreted as the method call $E.op(E')$. This holds also -for binary infix operators which start with a letter. The recursive call -to \verb@sort@ in the last quicksort example is thus equivalent to -\begin{verbatim} - sort(a.filter(x => x < pivot)) - .:::(sort(a.filter(x => x == pivot))) - .:::(sort(a.filter(x => x > pivot))) . -\end{verbatim} - -Looking again in detail at the first, imperative implementation of -Quicksort, we find that many of the language constructs used in the -second solution are also present, albeit in a disguised form. - -For instance, ``standard'' binary operators such as \verb@+@, -\verb@-@, or \verb@<@ are not treated in any special way. Like -\verb@append@, they are methods of their left operand. Consequently, -the expression \verb@i + 1@ is regarded as the invocation -\verb@i.+(1)@ of the \verb@+@ method of the integer value \verb@x@. -Of course, a compiler is free (if it is moderately smart, even expected) -to recognize the special case of calling the \verb@+@ method over -integer arguments and to generate efficient inline code for it. - -Control constructs such as \verb@while@ are also not primitive but are -predefined functions in the standard Scala library. Here is the -definition of \verb@while@ in Scala. -\begin{verbatim} -def while (def p: boolean) (def s: unit): unit = if (p) { s ; while(p)(s) } -\end{verbatim} -The \verb@while@ function takes as first parameter a test function, -which takes no parameters and yields a boolean value. As second -parameter it takes a command function which also takes no parameters -and yields a trivial result. \verb@while@ invokes the command function -as long as the test function yields true. Again, compilers are free to -pick specialized implementations of \verb@while@ that have the same -behavior as the invocation of the function given above. - -\chapter{\label{chap:example-auction}Programming with Actors and Messages} - -Here's an example that shows an application area for which Scala is -particularly well suited. Consider the task of implementing an -electronic auction service. We use an Erlang-style actor process -model to implement the participants of the auction. Actors are -objects to which messages are sent. Every process has a ``mailbox'' of -its incoming messages which is represented as a queue. It can work -sequentially through the messages in its mailbox, or search for -messages matching some pattern. - -For every traded item there is an auctioneer process that publishes -information about the traded item, that accepts offers from clients -and that communicates with the seller and winning bidder to close the -transaction. We present an overview of a simple implementation -here. - -As a first step, we define the messages that are exchanged during an -auction. There are two abstract base classes (called {\em traits}): -\verb@AuctionMessage@ for messages from clients to the auction -service, and \verb@AuctionReply@ for replies from the service to the -clients. These are defined as follows. -\begin{verbatim} -trait AuctionMessage; -case class - Offer(bid: int, client: Actor), \=// make a bid - Inquire(client: Actor) extends AuctionMessage; \>// inquire status - -trait AuctionReply; -case class - Status(asked: int, expiration: Date), \>// asked sum, expiration date - BestOffer, \>// yours is the best offer - BeatenOffer(maxBid: int), \>// offer beaten by maxBid - AuctionConcluded(seller: Actor, client: Actor), \>// auction concluded - AuctionFailed, \>// failed with no bids - AuctionOver extends AuctionReply; \>// bidding is closed -\end{verbatim} - -\begin{figure}[htb] -\begin{verbatim} -class Auction(seller: Actor, minBid: int, closing: Date) extends Actor { - val timeToShutdown = 36000000; // msec - val bidIncrement = 10; - def execute { - var maxBid = minBid - bidIncrement; - var maxBidder: Actor = _; - var running = true; - while (running) { - receiveWithin ((closing.getTime() - new Date().getTime())) { - case Offer(bid, client) => - if (bid >= maxBid + bidIncrement) { - if (maxBid >= minBid) maxBidder send BeatenOffer(bid); - maxBid = bid; maxBidder = client; client send BestOffer; - } else { - client send BeatenOffer(maxBid); - } - - case Inquire(client) => - client send Status(maxBid, closing); - - case TIMEOUT => - if (maxBid >= minBid) { - val reply = AuctionConcluded(seller, maxBidder); - maxBidder send reply; seller send reply; - } else { - seller send AuctionFailed; - } - receiveWithin(timeToShutdown) { - case Offer(_, client) => client send AuctionOver - case TIMEOUT => running = false; - }}}}} -\end{verbatim} -\caption{\label{fig:simple-auction}Implementation of an Auction Service} -\end{figure} - -For each base class, there are a number of {\em case classes} which -define the format of particular messages in the class. These messages -might well be ultimately mapped to small XML documents. We expect -automatic tools to exist that convert between XML documents and -internal data structures like the ones defined above. - -Figure~\ref{fig:simple-auction} presents a Scala implementation of a -class \verb@Auction@ for auction processes that coordinate the bidding -on one item. Objects of this class are created by indicating -\begin{itemize} -\item -a seller process which needs to be notified when the auction is over, -\item -a minimal bid, -\item -the date when the auction is to be closed. -\end{itemize} -The process behavior is defined by its \verb@run@ method. That method -repeatedly selects (using \verb@receiveWithin@) a message and reacts to it, -until the auction is closed, which is signalled by a \verb@TIMEOUT@ -message. Before finally stopping, it stays active for another period -determined by the \verb@timeToShutdown@ constant and replies to -further offers that the auction is closed. - -Here are some further explanations of the constructs used in this -program: -\begin{itemize} -\item -The \verb@receiveWithin@ method of class \verb@Actor@ takes as -parameters a time span given in milliseconds and a function that -processes messages in the mailbox. The function is given by a sequence -of cases that each specify a pattern and an action to perform for -messages matching the pattern. The \verb@receiveWithin@ method selects -the first message in the mailbox which matches one of these patterns -and applies the corresponding action to it. -\item -The last case of \verb@receiveWithin@ is guarded by a -\verb@TIMEOUT@ pattern. If no other messages are received in the meantime, this -pattern is triggered after the time span which is passed as argument -to the enclosing \verb@receiveWithin@ method. \verb@TIMEOUT@ is a -particular instance of class \verb@Message@, which is triggered by the -\verb@Actor@ implementation itself. -\item -Reply messages are sent using syntax of the form -\verb@destination send SomeMessage@. \verb@send@ is used here as a -binary operator with a process and a message as arguments. This is -equivalent in Scala to the method call -\verb@destination.send(SomeMessage)@, i.e. the invocation of -the \verb@send@ of the destination process with the given message as -parameter. -\end{itemize} -The preceding discussion gave a flavor of distributed programming in -Scala. It might seem that Scala has a rich set of language constructs -that support actor processes, message sending and receiving, -programming with timeouts, etc. In fact, the opposite is true. All the -constructs discussed above are offered as methods in the library class -\verb@Actor@. That class is itself implemented in Scala, based on the underlying -thread model of the host language (e.g. Java, or .NET). -The implementation of all features of class \verb@Actor@ used here is -given in Section~\ref{sec:actors}. - -The advantages of this approach are relative simplicity of the core -language and flexibility for library designers. Because the core -language need not specify details of high-level process communication, -it can be kept simpler and more general. Because the particular model -of messages in a mailbox is a library module, it can be freely -modified if a different model is needed in some applications. The -approach requires however that the core language is expressive enough -to provide the necessary language abstractions in a convenient -way. Scala has been designed with this in mind; one of its major -design goals was that it should be flexible enough to act as a -convenient host language for domain specific languages implemented by -library modules. For instance, the actor communication constructs -presented above can be regarded as one such domain specific language, -which conceptually extends the Scala core. - -\chapter{\label{chap:simple-funs}Expressions and Simple Functions} - -The previous examples gave an impression of what can be done with -Scala. We now introduce its constructs one by one in a more -systematic fashion. We start with the smallest level, expressions and -functions. - -\section{Expressions And Simple Functions} - -A Scala system comes with an interpreter which can be seen as a -fancy calculator. A user interacts with the calculator by typing in -expressions and obtaining the results of their evaluation. Example: - -\begin{verbatim} -? 87 + 145 -232 - -? 1000 - 333 -667 - -? 5 + 2 * 3 -11 -\end{verbatim} -It is also possible to name a sub-expression and use the name instead -of the expression afterwards: -\begin{verbatim} -? def size = 2 -def size: int - -? 5 * size -10 -\end{verbatim} -\begin{verbatim} -? def pi = 3.14159 -def pi: double - -? def radius = 10 -def radius: int - - -? 2 * pi * radius -62.8318 -\end{verbatim} -Definitions start with the reserved word \verb@def@; they introduce a -name which stands for the expression following the \verb@=@ sign. The -interpreter will answer with the introduced name and its type. - -Executing a definition such as \verb@def x = e@ will not evaluate the -expression \verb@e@. Instead \verb@e@ is evaluated whenever \verb@x@ -is used. Alternatively, Scala offers a value definition -\verb@val x = e@, which does evaluate the right-hand-side \verb@e@ as part of the -evaluation of the definition. If \verb@x@ is then used subsequently, -it is immediately replaced by the pre-computed value of -\verb@e@, so that the expression need not be evaluated again. - -How are expressions evaluated? An expression consisting of operators -and operands is evaluated by repeatedly applying the following -simplification steps. -\begin{itemize} -\item pick the left-most operation -\item evaluate its operands -\item apply the operator to the operand values. -\end{itemize} -A name defined by \verb@def@\ is evaluated by replacing the name by the -definition's right hand side. A name defined by \verb@val@ is -evaluated by replacing the name by the value of the definitions's -right-hand side. The evaluation process stops once we have reached a -value. A value is some data item such as a string, a number, an array, -or a list. - -\example -Here is an evaluation of an arithmetic expression. -\begin{verbatim} - \=(2 * pi) * radius --> \>(2 * 3.14159) * radius --> \>6.28318 * radius --> \>6.28318 * 10 --> \>62.8318 -\end{verbatim} -The process of stepwise simplification of expressions to values is -called {\em reduction}. - -\section{Parameters} - -Using \verb@def@, one can also define functions with parameters. Example: -\begin{verbatim} -? def square(x: double) = x * x -def square(x: double): double - -? square(2) -4.0 - -? square(5 + 4) -81.0 - -? square(square(4)) -256.0 - -? def sumOfSquares(x: double, y: double) = square(x) + square(y) -def sumOfSquares(x: double, y: double): double -\end{verbatim} - -Function parameters follow the function name and are always enclosed -in parentheses. Every parameter comes with a type, which is indicated -following the parameter name and a colon. At the present time, we only -need basic numeric types such as the type \verb@double@ of double -precision numbers. These are written as in Java. - -Functions with parameters are evaluated analogously to operators in -expressions. First, the arguments of the function are evaluated (in -left-to-right order). Then, the function application is replaced by -the function's right hand side, and at the same time all formal -parameters of the function are replaced by their corresponding actual -arguments. - -\example\ - -\begin{verbatim} - \=sumOfSquares(3, 2+2) --> \>sumOfSquares(3, 4) --> \>square(3) + square(4) --> \>3 * 3 + square(4) --> \>9 + square(4) --> \>9 + 4 * 4 --> \>9 + 16 --> \>25 -\end{verbatim} - -The example shows that the interpreter reduces function arguments to -values before rewriting the function application. One could instead -have chosen to apply the function to unreduced arguments. This would -have yielded the following reduction sequence: -\begin{verbatim} - \= sumOfSquares(3, 2+2) --> \>square(3) + square(2+2) --> \>3 * 3 + square(2+2) --> \>9 + square(2+2) --> \>9 + (2+2) * (2+2) --> \>9 + 4 * (2+2) --> \>9 + 4 * 4 --> \>9 + 16 --> \>25 -\end{verbatim} - -The second evaluation order is known as \emph{call-by-name}, -whereas the first one is known as \emph{call-by-value}. For -expressions that use only pure functions and that therefore can be -reduced with the substitution model, both schemes yield the same final -values. - -Call-by-value has the advantage that it avoids repeated evaluation of -arguments. Call-by-name has the advantage that it avoids evaluation of -arguments when the parameter is not used at all by the function. -Call-by-value is usually more efficient than call-by-name, but a -call-by-value evaluation might loop where a call-by-name evaluation -would terminate. Consider: -\begin{verbatim} -? def loop: int = loop -def loop: int - -? def first(x: int, y: int) = x -def first(x: int, y: int): int -\end{verbatim} -Then \verb@first(1, loop)@ reduces with call-by-name to \verb@1@, -whereas the same term reduces with call-by-value repeatedly to itself, -hence evaluation does not terminate. -\begin{verbatim} - \=first(1, loop) --> \>first(1, loop) --> \>first(1, loop) --> \>... -\end{verbatim} -Scala uses call-by-value by default, but it switches to call-by-name evaluation -if the parameter is preceded by \verb@def@. - -\example\ - -\begin{verbatim} -? def constOne(x: int, def y: int) = 1 -constOne(x: int, def y: int): int - -? constOne(1, loop) -1 - -? constOne(loop, 2) // gives an infinite loop. -^C -\end{verbatim} - -\section{Conditional Expressions} - -Scala's \verb@if-else@ lets one choose between two alternatives. Its -syntax is like Java's \verb@if-else@. But where Java's \verb@if-else@ -can be used only as an alternative of statements, Scala allows the -same syntax to choose between two expressions. Scala's \verb@if-else@ -hence also replaces Java's conditional expression \verb@ ... ? ... : -...@. - -\example\ - -\begin{verbatim} -? def abs(x: double) = if (x >= 0) x else -x -abs(x: double): double -\end{verbatim} -Scala's boolean expressions are similar to Java's; they are formed -from the constants -\verb@true@ and -\verb@false@, comparison operators, boolean negation \verb@!@ and the -boolean operators \verb@&&@ and \verb@||@. - -\section{\label{sec:sqrt}Example: Square Roots by Newton's Method} - -We now illustrate the language elements introduced so far in the -construction of a more interesting program. The task is to write a -function -\begin{verbatim} -def sqrt(x: double): double = ... -\end{verbatim} -which computes the square root of \verb@x@. - -A common way to compute square roots is by Newton's method of -successive approximations. One starts with an initial guess \verb@y@ -(say: \verb@y = 1@). One then repeatedly improves the current guess -\verb@y@ by taking the average of \verb@y@ and \verb@x/y@. -As an example, the next three columns indicate the guess \verb@y@, the -quotient \verb@x/y@, and their average for the first approximations of -$\sqrt 2$. -\begin{verbatim} -1 \=2/1 = 2 \=1.5 -1.5 \>2/1.5 = 1.3333 \>1.4167 -1.4167 \>2/1.4167 = 1.4118 \>1.4142 -1.4142 \>... \>... - -y \>x/y \>(y + x/y)/2 -\end{verbatim} -One can implement this algorithm in Scala by a set of small functions, -which each represent one of the elements of the algorithm. - -We first define a function for iterating from a guess to the result: -\begin{verbatim} -def sqrtIter(guess: double, x: double): double = - if (isGoodEnough(guess, x)) guess - else sqrtIter(improve(guess, x), x); -\end{verbatim} -Note that \verb@sqrtIter@ calls itself recursively. Loops in -imperative programs can always be modelled by recursion in functional -programs. - -Note also that the definition of \verb@sqrtIter@ contains a return -type, which follows the parameter section. Such return types are -mandatory for recursive functions. For a non-recursive function, the -return type is optional; if it is missing the type checker will -compute it from the type of the function's right-hand side. However, -even for non-recursive functions it is often a good idea to include a -return type for better documentation. - -As a second step, we define the two functions called by -\verb@sqrtIter@: a function to \verb@improve@ the guess and a -termination test \verb@isGoodEnough@. Here's their definition. -\begin{verbatim} -def improve(guess: double, x: double) = - (guess + x / guess) / 2; - -def isGoodEnough(guess: double, x: double) = - abs(square(guess) - x) < 0.001; -\end{verbatim} - -Finally, the \verb@sqrt@ function itself is defined by an aplication -of \verb@sqrtIter@. -\begin{verbatim} -def sqrt(x: double) = sqrtIter(1.0, x); -\end{verbatim} - -\exercise The \verb@isGoodEnough@ test is not very precise for small numbers -and might lead to non-termination for very large ones (why?). -Design a different version \verb@isGoodEnough@ which does not have these problems. - -\exercise Trace the execution of the \verb@sqrt(4)@ expression. - -\section{Nested Functions} - -The functional programming style encourages the construction of many -small helper functions. In the last example, the implementation -of \verb@sqrt@ made use of the helper functions -\verb@sqrtIter@, \verb@improve@ and -\verb@isGoodEnough@. The names of these functions -are relevant only for the implementation of -\verb@sqrt@. We normally do not want users of \verb@sqrt@ to acess these functions -directly. - -We can enforce this (and avoid name-space pollution) by including -the helper functions within the calling function itself: -\begin{verbatim} -def sqrt(x: double) = { - def sqrtIter(guess: double, x: double): double = - if (isGoodEnough(guess, x)) guess - else sqrtIter(improve(guess, x), x); - - def improve(guess: double, x: double) = - (guess + x / guess) / 2; - - def isGoodEnough(guess: double, x: double) = - abs(square(guess) - x) < 0.001; - - sqrtIter(1.0, x) -} -\end{verbatim} -In this program, the braces \verb@{ ... }@ enclose a {\em block}. -Blocks in Scala are themselves expressions. Every block ends in a -result expression which defines its value. The result expression may -be preceded by auxiliary definitions, which are visible only in the -block itself. - -Every definition in a block must be followed by a semicolon, which -separates this definition from subsequent definitions or the result -expression. However, a semicolon is inserted implicitly if the -definition ends in a right brace and is followed by a new line. -Therefore, the following are all legal: -\begin{verbatim} -def f(x) = x + 1; /* `;' mandatory */ -f(1) + f(2) - -def g(x) = {x + 1} -g(1) + g(2) - -def h(x) = {x + 1}; /* `;' mandatory */ h(1) + h(2) -\end{verbatim} -Scala uses the usual block-structured scoping rules. A name defined in -some outer block is visible also in some inner block, provided it is -not redefined there. This rule permits us to simplify our -\verb@sqrt@ example. We need not pass \verb@x@ around as an additional parameter of -the nested functions, since it is always visible in them as a -parameter of the outer function \verb@sqrt@. Here is the simplified code: -\begin{verbatim} -def sqrt(x: double) = { - def sqrtIter(guess: double): double = - if (isGoodEnough(guess)) guess - else sqrtIter(improve(guess)); - - def improve(guess: double) = - (guess + x / guess) / 2; - - def isGoodEnough(guess: double) = - abs(square(guess) - x) < 0.001; - - sqrtIter(1.0) -} -\end{verbatim} - -\section{Tail Recursion} - -Consider the following function to compute the greatest common divisor -of two given numbers. - -\begin{verbatim} -def gcd(a: int, b: int): int = if (b == 0) a else gcd(b, a % b) -\end{verbatim} - -Using our substitution model of function evaluation, -\verb@gcd(14, 21)@ evaluates as follows: - -\begin{verbatim} - \=gcd(14, 21) --> \>if (21 == 0) 14 else gcd(21, 14 % 21) --> \>if (false) 14 else gcd(21, 14 % 21) --> \>gcd(21, 14 % 21) --> \>gcd(21, 14) --> \>if (14 == 0) 21 else gcd(14, 21 % 14) --> -> \>gcd(14, 21 % 14) --> \>gcd(14, 7) --> \>if (7 == 0) 14 else gcd(7, 14 % 7) --> -> \>gcd(7, 14 % 7) --> \>gcd(7, 0) --> \>if (0 == 0) 7 else gcd(0, 7 % 0) --> -> \>7 -\end{verbatim} - -Contrast this with the evaluation of another recursive function, -\verb@factorial@: - -\begin{verbatim} -def factorial(n: int): int = if (n == 0) 1 else n * factorial(n - 1) -\end{verbatim} - -The application \verb@factorial(5)@ rewrites as follows: -\begin{verbatim} - \=factorial(5) --> \>if (5 == 0) 1 else 5 * factorial(5 - 1) --> \>5 * factorial(5 - 1) --> \>5 * factorial(4) --> ... -> \>5 * (4 * factorial(3)) --> ... -> \>5 * (4 * (3 * factorial(2))) --> ... -> \>5 * (4 * (3 * (2 * factorial(1)))) --> ... -> \>5 * (4 * (3 * (2 * (1 * factorial(0)))) --> ... -> \>5 * (4 * (3 * (2 * (1 * 1)))) --> ... -> \>120 - -\end{verbatim} -There is an important difference between the two rewrite sequences: -The terms in the rewrite sequence of \verb@gcd@ have again and again -the same form. As evaluation proceeds, their size is bounded by a -constant. By contrast, in the evaluation of factorial we get longer -and longer chains of operands which are then multiplied in the last -part of the evaluation sequence. - -Even though actual implementations of Scala do not work by rewriting -terms, they nevertheless should have the same space behavior as in the -rewrite sequences. In the implementation of \verb@gcd@, one notes that -the recursive call to \verb@gcd@ is the last action performed in the -evaluation of its body. One also says that \verb@gcd@ is -``tail-recursive''. The final call in a tail-recursive function can be -implemented by a jump back to the beginning of that function. The -arguments of that call can overwrite the parameters of the current -instantiation of \verb@gcd@, so that no new stack space is needed. -Hence, tail recursive functions are iterative processes, which can be -executed in constant space. - -By contrast, the recursive call in \verb@factorial@ is followed by a -multiplication. Hence, a new stack frame is allocated for the -recursive instance of factorial, and is decallocated 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. - -More generally, if the last action of a function is a call to another -(possibly the same) function, only a single stack frame is needed for -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 -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 also, -but one should not rely on this across -implementations\footnote{The current Scala implementation is not yet -production quality; it never optimizes tail calls, not even directly -recursive ones}. - -\exercise Design a tail-recursive version of -\verb@factorial@. - -\chapter{\label{chap:first-class-funs}First-Class Functions} - -A function in Scala is a ``first-class value''. Like any other value, -it may be passed as a parameter or returned as a result. Functions -which take other functions as parameters or return them as results are -called {\em higher-order} functions. This chapter introduces -higher-order functions and shows how they provide a flexible mechanism -for program composition. - -As a motivating example, consider the following three related tasks: -\begin{enumerate} -\item -Write a function to sum all integers between two given numbers \verb@a@ and \verb@b@: -\begin{verbatim} -def sumInts(a: int, b: int): double = - if (a > b) 0 else a + sumInts(a + 1, b) -\end{verbatim} -\item -Write a function to sum the cubes of all integers between two given numbers -\verb@a@ and \verb@b@: -\begin{verbatim} -def cube(x: int): double = x * x * x -def sumCubes(a: int, b: int): double = - if (a > b) 0 else cube(a) + sumSqrts(a + 1, b) -\end{verbatim} -\item -Write a function to sum the reciprocals of all integers between two given numbers -\verb@a@ and \verb@b@: -\begin{verbatim} -def sumReciprocals(a: int, b: int): double = - if (a > b) 0 else 1.0 / a + sumReciprocals(a + 1, b) -\end{verbatim} -\end{enumerate} -These functions are all instances of -\(\sum^b_a f(n)\) for different values of $f$. -We can factor out the common pattern by defining a function \verb@sum@: -\begin{verbatim} -def sum(f: int => double, a: int, b: int): double = - if (a > b) 0 else f(a) + sum(f, a + 1, b) -\end{verbatim} -The type \verb@int => double@ is the type of functions that -take arguments of type \verb@int@ and return results of type -\verb@double@. So \verb@sum@ is a function which takes another function as -a parameter. In other words, \verb@sum@ is a {\em higher-order} -function. - -Using \verb@sum@, we can formulate the three summing functions as -follows. -\begin{verbatim} -def sumInts(a: int, b: int): double = sum(id, a, b); -def sumCubes(a: int, b: int): double = sum(cube, a, b); -def sumReciprocals(a: int, b: int): double = sum(reciprocal, a, b); -\end{verbatim} -where -\begin{verbatim} -def id(x: int): double = x; -def cube(x: int): double = x * x * x; -def reciprocal(x: int): double = 1.0/x; -\end{verbatim} - -\section{Anonymous Functions} - -Parameterization by functions tends to create many small functions. In -the previous example, we defined \verb@id@, \verb@cube@ and -\verb@reciprocal@ as separate functions, so that they could be -passed as arguments to \verb@sum@. - -Instead of using named function definitions for these small argument -functions, we can formulate them in a shorter way as {\em anonymous -functions}. An anonymous function is an expression that evaluates to a -function; the function is defined without giving it a name. As an -example consider the anonymous reciprocal function: -\begin{verbatim} - x: int => 1.0/x -\end{verbatim} -The part before the arrow `\verb@=>@' is the parameter of the function, -whereas the part following the `\verb@=>@' is its body. If there are -several parameters, we need to enclose them in parentheses. For -instance, here is an anonymous function which multiples its two arguments. -\begin{verbatim} - (x: double, y: double) => x * y -\end{verbatim} -Using anonymous functions, we can reformulate the three summation -functions without named auxiliary functions: -\begin{verbatim} -def sumInts(a: int, b: int): double = sum(x: int => x, a, b); -def sumCubes(a: int, b: int): double = sum(x: int => x * x * x, a, b); -def sumReciprocals(a: int, b: int): double = sum(x: int => 1.0/x, a, b); -\end{verbatim} -Often, the Scala compiler can deduce the parameter type(s) from the -context of the anonymous function. In this case, they can be omitted. -For instance, in the case of \verb@sumInts@, \verb@sumCubes@ and -\verb@sumReciprocals@, one knows from the type of -\verb@sum@ that the first parameter must be a function of type -\verb@int => double@. Hence, the parameter type \verb@int@ is -redundant and may be omitted: -\begin{verbatim} -def sumInts(a: int, b: int): double = sum(x => x, a, b); -def sumCubes(a: int, b: int): double = sum(x => x * x * x, a, b); -def sumReciprocals(a: int, b: int): double = sum(x => 1.0/x, a, b); -\end{verbatim} - -Generally, the Scala term -\verb@(x$_1$: T$_1$, ..., x$_n$: T$_n$) => E@ -defines a function which maps its parameters -\verb@x$_1$, ..., x$_n$@ to the result of the expression \verb@E@ -(where \verb@E@ may refer to \verb@x$_1$, ..., x$_n$@). Anonymous -functions are not essential language elements of Scala, as they can -always be expressed in terms of named functions. Indeed, the -anonymous function -\verb@(x$_1$: T$_1$, ..., x$_n$: T$_n$) => E@ -is equivalent to the block -\begin{verbatim} -{ def f (x$_1$: T$_1$, ..., x$_n$: T$_n$) = E ; f } -\end{verbatim} -where \verb@f@ is fresh name which is used nowhere else in the program. -We also say, anonymous functions are ``syntactic sugar''. - -\section{Currying} - -The latest formulation of the three summing function is already quite -compact. But we can do even better. Note that -\verb@a@ and \verb@b@ appear as parameters and arguments of every function -but they do not seem to take part in interesting combinations. Is -there a way to get rid of them? - -Let's try to rewrite \verb@sum@ so that it does not take the bounds -\verb@a@ and \verb@b@ as parameters: -\begin{verbatim} -def sum(f: int => double) = { - def sumF(a: int, b: int): double = - if (a > b) 0 else f(a) + sumF(a + 1, b); - sumF -} -\end{verbatim} -In this formulation, \verb@sum@ is a function which returns another -function, namely the specialized summing function \verb@sumF@. This -latter function does all the work; it takes the bounds \verb@a@ and -\verb@b@ as parameters, applies \verb@sum@'s function parameter \verb@f@ to all -integers between them, and sums up the results. - -Using this new formulation of \verb@sum@, we can now define: -\begin{verbatim} -def sumInts = sum(x => x); -def sumCubes = sum(x => x * x * x); -def sumReciprocals = sum(x => 1.0/x); -\end{verbatim} -Or, equivalently, with value definitions: -\begin{verbatim} -val sumInts = sum(x => x); -val sumCubes = sum(x => x * x * x); -val sumReciprocals = sum(x => 1.0/x); -\end{verbatim} -These functions can be applied like other functions. For instance, -\begin{verbatim} -? sumCubes(1, 10) + sumReciprocals (10, 20) -3025.7687714031754 -\end{verbatim} -How are function-returning functions applied? As an example, in the expression -\begin{verbatim} -sum (x => x * x * x) (1, 10) , -\end{verbatim} -the function \verb@sum@ is applied to the cubing function -\verb@(x => x * x * x)@. The resulting function is then -applied to the second argument list, \verb@(1, 10)@. - -This notation is possible because function application associates to the left. -That is, if $args_1$ and $args_2$ are argument lists, then -\bda{lcl} -f(args_1)(args_2) & \ \ \mbox{is equivalent to}\ \ & (f(args_1))(args_2) -\eda -In our example, \verb@sum(x => x * x * x)(1, 10)@ is equivalent to -\verb@(sum(x => x * x * x))(1, 10)@. - -The style of function-returning functions is so useful that Scala has -special syntax for it. For instance, the next definition of \verb@sum@ -is equivalent to the previous one, but is shorter: -\begin{verbatim} -def sum(f: int => double)(a: int, b: int): double = - if (a > b) 0 else f(a) + sum(f)(a + 1, b) -\end{verbatim} -Generally, a curried function definition -\begin{verbatim} -def f (args$_1$) ... (args$_n$) = E -\end{verbatim} -where $n > 1$ expands to -\begin{verbatim} -def f (args$_1$) ... (args$_{n-1}$) = { def g (args$_n$) = E ; g } -\end{verbatim} -where \verb@g@ is a fresh identifier. Or, shorter, using an anonymous function: -\begin{verbatim} -def f (args$_1$) ... (args$_{n-1}$) = ( args$_n$ ) => E . -\end{verbatim} -Performing this step $n$ times yields that -\begin{verbatim} -def f (args$_1$) ... (args$_n$) = E -\end{verbatim} -is equivalent to -\begin{verbatim} -def f = (args$_1$) => ... => (args$_n$) => E . -\end{verbatim} -Or, equivalently, using a value definition: -\begin{verbatim} -val f = (args$_1$) => ... => (args$_n$) => E . -\end{verbatim} -This style of function definition and application is called {\em -currying} after its promoter, Haskell B.\ Curry, a logician of the -20th century, even though the idea goes back further to Moses -Sch\"onfinkel and Gottlob Frege. - -The type of a function-returning function is expressed analogously to -its parameter list. Taking the last formulation of \verb@sum@ as an example, -the type of \verb@sum@ is \verb@(int => double) => (int, int) => double@. -This is possible because function types associate to the right. I.e. -\begin{verbatim} -T$_1$ => T$_2$ => T$_3$ \=$\mbox{is equivalent to}$ \=T$_1$ => (T$_2$ => T$_3$) . -\end{verbatim} - -\subsection*{Exercises:} - -1. The \verb@sum@ function uses a linear recursion. Can you write a -tail-recursive one by filling in the ??'s? - -\begin{verbatim} -def sum(f: int => double)(a: int, b: int): double = { - def iter (a, result) = { - if (??) ?? - else iter (??, ??) - } - iter (??, ??) -} -\end{verbatim} - -2. Write a function \verb@product@ that computes the product of the -values of functions at points over a given range. - -3. Write \verb@factorial@ in terms of \verb@product@. - -4. Can you write an even more general function which generalizes both -\verb@sum@ and \verb@product@? - -\section{Example: Finding Fixed Points of Functions} - -A number \verb@x@ is called a {\em fixed point} of a function \verb@f@ if -\begin{verbatim} -f(x) = x . -\end{verbatim} -For some functions \verb@f@ we can locate the fixed point by beginning -with an initial guess and then applying \verb@f@ repeatedly, until the -value does not change anymore (or the change is within a small -tolerance). This is possible if the sequence -\begin{verbatim} -x, f(x), f(f(x)), f(f(f(x))), ... -\end{verbatim} -converges to fixed point of $f$. This idea is captured in -the following ``fixed-point finding function'': -\begin{verbatim} -val tolerance = 0.0001; -def isCloseEnough(x: double, y: double) = abs((x - y) / x) < tolerance; -def fixedPoint(f: double => double)(firstGuess: double) = { - def iterate(guess: double): double = { - val next = f(guess); - if (isCloseEnough(guess, next)) next - else iterate(next) - } - iterate(firstGuess) -} -\end{verbatim} -We now apply this idea in a reformulation of the square root function. -Let's start with a specification of \verb@sqrt@: -\begin{verbatim} -sqrt(x) \== $\mbox{the {\sl y} such that}$ y * y = x - \>= $\mbox{the {\sl y} such that}$ y = x / y -\end{verbatim} -Hence, \verb@sqrt(x)@ is a fixed point of the function \verb@y => x / y@. -This suggests that \verb@sqrt(x)@ can be computed by fixed point iteration: -\begin{verbatim} -def sqrt(x: double) = fixedPoint(y => x / y)(1.0) -\end{verbatim} -Unfortunately, this does not converge. Let's instrument the fixed point -function with a print statement which keeps track of the current -\verb@guess@ value: -\begin{verbatim} -def fixedPoint(f: double => double)(firstGuess: double) = { - def iterate(guess: double): double = { - val next = f(guess); - System.out.println(next); - if (isCloseEnough(guess, next)) next - else iterate(next) - } - iterate(firstGuess) -} -\end{verbatim} -Then, \verb@sqrt(2)@ yields: -\begin{verbatim} - 2.0 - 1.0 - 2.0 - 1.0 - 2.0 - ... -\end{verbatim} -One way to control such oscillations is to prevent the guess from changing too much. -This can be achieved by {\em averaging} successive values of the original sequence: -\begin{verbatim} -> def sqrt(x: double) = fixedPoint(y => (y + x/y) / 2)(1.0) -> sqrt(2.0) - 1.5 - 1.4166666666666665 - 1.4142156862745097 - 1.4142135623746899 - 1.4142135623746899 -\end{verbatim} -In fact, expanding the \verb@fixedPoint@ function yields exactly our -previous definition of fixed point from Section~\ref{sec:sqrt}. - -The previous examples showed that the expressive power of a language -is considerably enhanced if functions can be passed as arguments. The -next example shows that functions which return functions can also be -very useful. - -Consider again fixed point iterations. We started with the observation -that $\sqrt(x)$ is a fixed point of the function \verb@y => x / y@. -Then we made the iteration converge by averaging successive values. -This technique of {\em average dampening} is so general that it -can be wrapped in another function. -\begin{verbatim} -def averageDamp(f: double => double)(x: double) = (x + f(x)) / 2 -\end{verbatim} -Using \verb@averageDamp@, we can reformulate the square root function -as follows. -\begin{verbatim} -def sqrt(x: double) = fixedPoint(averageDamp(y => x/y))(1.0) -\end{verbatim} -This expresses the elements of the algorithm as clearly as possible. - -\exercise Write a function for cube roots using \verb@fixedPoint@ and -\verb@averageDamp@. - -\section{Summary} - -We have seen in the previous chapter that functions are essential -abstractions, because they permit us to introduce general methods of -computing as explicit, named elements in our programming language. -The current chapter has shown that these abstractions can be combined by -higher-order functions to create further abstractions. As -programmers, we should look out for opportunities to abstract and to -reuse. The highest possible level of abstraction is not always the -best, but it is important to know abstraction techniques, so that one -can use abstractions where appropriate. - -\section{Language Elements Seen So Far} - -Chapters~\ref{chap:simple-funs} and \ref{chap:first-class-funs} have -covered Scala's language elements to express expressions and types -comprising of primitive data and functions. The context-free syntax -of these language elements is given below in extended Backus-Naur -form, where `\verb@|@' denotes alternatives, \verb@[...]@ denotes -option (0 or 1 occurrences), and \verb@{...}@ denotes repetition (0 or -more occurrences). - -\subsection*{Characters} - -Scala programs are sequences of (Unicode) characters. We distinguish the -following character sets: -\begin{itemize} -\item -whitespace, such as `\verb@ @', tabulator, or newline characters, -\item -letters `\verb@a@' to `\verb@z@', `\verb@A@' to `\verb@Z@', -\item -digits \verb@`0'@ to `\verb@9@', -\item -the delimiter characters -\begin{verbatim} -. , ; ( ) { } [ ] \ " ' -\end{verbatim} -\item -operator characters, such as `\verb@#@' `\verb@+@', -`\verb@:@'. Essentially, these are printable characters which are -in none of the character sets above. -\end{itemize} - -\subsection*{Lexemes:} - -\begin{verbatim} -ident ::= letter {letter | digit} | operator { operator } | ident `_' ident -literal ::= $\mbox{``as in Java''}$ -\end{verbatim} - -Literals are as in Java. They define numbers, characters, strings, or -boolean values. Examples of literals as \verb@0@, \verb@1.0d10@, \verb@'x'@, -\verb@"he said \"hi!\""@, or \verb@true@. - -Identifiers can be of two forms. They either start with a letter, -which is followed by a (possibly empty) sequence of letters or -symbols, or they start with an operator character, which is followed -by a (possibly empty) sequence of operator characters. Both forms of -identifiers may contain underscore characters `\verb@_@'. Furthermore, -an underscore character may be followed by either sort of -identifier. Hence, the following are all legal identifiers: -\begin{verbatim} -x Room10a + -- foldl_: +_vector -\end{verbatim} -It follows from this rule that subsequent operator-identifiers need to -be separated by whitespace. For instance, the input -\verb@x+-y@ is parsed as the three token sequence \verb@x@, \verb@+-@, -\verb@y@. If we want to express the sum of \verb@x@ with the -negated value of \verb@y@, we need to add at least one space, -e.g. \verb@x+ -y@. - -The `\verb@\$@' character is reserved for compiler-generated -identifiers; it should not be used in source programs. %$ - -The following are reserved words, they may not be used as identifiers: -\begin{verbatim} -abstract case catch class def -do else extends false final -finally for if import new -null object override package private -protected return sealed super this -trait try true type val -var while with yield -_ : = => <- <: >: # @ -\end{verbatim} - -\subsection*{Types:} - -\begin{verbatim} -Type \= = SimpleType | FunctionType -FunctionType \> = SimpleType `=>' Type | `(' [Types] `)' `=>' Type -SimpleType \> = byte | short | char | int | long | double | float | boolean | unit | String -Types \> = Type {`,' Type} -\end{verbatim} - -Types can be: -\begin{itemize} -\item number types \verb@byte@, \verb@short@, \verb@char@, \verb@int@, \verb@long@, \verb@float@ and \verb@double@ (these are as in Java), -\item the type \verb@boolean@ with values \verb@true@ and \verb@false@, -\item the type \verb@unit@ with the only value \verb@{}@, -\item the type \verb@String@, -\item function types such as \verb@(int, int) => int@ or \verb@String => Int => String@. -\end{itemize} - -\subsection*{Expressions:} - -\begin{verbatim} -Expr \= = InfixExpr | FunctionExpr | if `(' Expr `)' Expr else Expr -InfixExpr \> = PrefixExpr | InfixExpr Operator InfixExpr -Operator \> = ident -PrefixExpr \> = [`+' | `-' | `!' | `~' ] SimpleExpr -SimpleExpr \> = ident | literal | SimpleExpr `.' ident | Block -FunctionExpr\> = Bindings `=> Expr -Bindings \> = ident [`:' SimpleType] | `(' [Binding {`,' Binding}] `)' -Binding \> = ident [`:' Type] -Block \> = `{' {Def `;'} Expr `}' -\end{verbatim} - -Expressions can be: -\begin{itemize} -\item -identifiers such as \verb@x@, \verb@isGoodEnough@, \verb@*@, or \verb@+-@, -\item -literals, such as \verb@0@, \verb@1.0@, or \verb@"abc"@, -\item -field and method selections, such as \verb@System.out.println@, -\item -function applications, such as \verb@sqrt(x)@, -\item -operator applications, such as \verb@-x@ or \verb@y + x@, -\item -conditionals, such as \verb@if (x < 0) -x else x@, -\item -blocks, such as \verb@{ val x = abs(y) ; x * 2 }@, -\item -anonymous functions, such as \verb@x => x + 1@ or \verb@(x: int, y: int) => x + y@. -\end{itemize} - -\subsection*{Definitions:} - -\begin{verbatim} -Def \= = \=FunDef | ValDef -FunDef \> = \>def ident {`(' [Parameters] `)'} [`:' Type] `=' Expr -ValDef \> = \>val ident [`:' Type] `=' Expr -Parameters \> = \>Parameter {`,' Parameter} -Parameter \> = \>[def] ident `:' Type -\end{verbatim} -Definitions can be: -\begin{itemize} -\item -function definitions such as \verb@def square(x: int) = x * x@, -\item -value definitions such as \verb@val y = square(2)@. -\end{itemize} - -\chapter{Classes and Objects} -\label{chap:classes} - -Scala does not have a built-in type of rational numbers, but it is -easy to define one, using a class. Here's a possible implementation. - -\begin{verbatim} -class Rational(n: int, d: int) { - private def gcd(x: int, y: int): int = { - if (x == 0) y - else if (x < 0) gcd(-x, y) - else if (y < 0) -gcd(x, -y) - else gcd(y % x, x); - } - private val g = gcd(n, d); - - val numer: int = n/g; - val denom: int = d/g; - def +(that: Rational) = - new Rational(numer * that.denom + that.numer * denom, denom * that.denom); - def -(that: Rational) = - new Rational(numer * that.denom - that.numer * denom, denom * that.denom); - def *(that: Rational) = - new Rational(numer * that.numer, denom * that.denom); - def /(that: Rational) = - new Rational(numer * that.denom, denom * that.numer); -} -\end{verbatim} -This defines \verb@Rational@ as a class which takes two constructor -arguments \verb@n@ and \verb@d@, containing the number's numerator and -denominator parts. The class provides fields which return these parts -as well as methods for arithmetic over rational numbers. Each -arithmetic method takes as parameter the right operand of the -operation. The left operand of the operation is always the rational -number of which the method is a member. - -\paragraph{Private members.} -The implementation of rational numbers defines a private method -\verb@gcd@ which computes the greatest common denominator of two -integers, as well as a private field \verb@g@ which contains the -\verb@gcd@ of the constructor arguments. These members are inaccessible -outside class \verb@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 -normalized form. - -\paragraph{Creating and Accessing Objects.} -As an example of how rational numbers can be used, here's a program -that prints the sum of all numbers $1/i$ where $i$ ranges from 1 to 10. -\begin{verbatim} -var i = 1; -var x = Rational(0, 1); -while (i <= 10) { - x = x + Rational(1,i); - i = i + 1; -} -System.out.println(x.numer + "/" + x.denom); -\end{verbatim} -The \verb@+@ operation converts both its operands to strings and returns the -concatenation of the result strings. It thus corresponds to \verb@+@ in Java. - -\paragraph{Inheritance and Overriding.} -Every class in Scala has a superclass which it extends. -Excepted is only the root class \verb@Object@, which does not have a -superclass, and which is indirectly extended by every other class. -If a class does not mention a superclass in its definition, the root -class \verb@Object@ is implicitly assumed. For instance, class -\verb@Rational@ could equivalently be defined as -\begin{verbatim} -class Rational(n: int, d: int) extends Object { - ... // as before -} -\end{verbatim} -A class inherits all members from its superclass. It may also redefine -(or: {\em override}) some inherited members. For instance, class -\verb@Object@ defines -a method -\verb@toString@ which returns a representation of the object as a string: -\begin{verbatim} -class Object { - ... - def toString(): String = ... -} -\end{verbatim} -The implementation of \verb@toString@ in \verb@Object@ -forms a string consisting of the object's class name and a number. It -makes sense to redefine this method for objects that are rational -numbers: -\begin{verbatim} -class Rational(n: int, d: int) extends Object { - ... // as before - override def toString() = numer + "/" + denom; -} -\end{verbatim} -Note that, unlike in Java, redefining definitions need to be preceded -by an \verb@override@ modifier. - -If class $A$ extends class $B$, then objects of type $A$ may be used -wherever objects of type $B$ are expected. We say in this case that -type $A$ {\em conforms} to type $B$. For instance, \verb@Rational@ -conforms to \verb@Object@, so it is legal to assign a \verb@Rational@ -value to a variable of type \verb@Object@: -\begin{verbatim} -var x: Object = new Rational(1,2); -\end{verbatim} - -\paragraph{Parameterless Methods.} -%Also unlike in Java, methods in Scala do not necessarily take a -%parameter list. An example is \verb@toString@; the method is invoked -%by simply mentioning its name. For instance: -%\begin{verbatim} -%val r = new Rational(1,2); -%System.out.println(r.toString()); // prints``1/2'' -%\end{verbatim} -Also unlike in Java, methods in Scala do not necessarily take a -parameter list. An example is the \verb@square@ method below. This -method is invoked by simply mentioning its name. -\begin{verbatim} -class Rational(n: int, d: int) extends Object { - ... // as before - def square = Rational(numer*numer, denom*denom); -} -val r = new Rational(3,4); -System.out.println(r.square); // prints``9/16'' -\end{verbatim} -That is, parameterless methods are accessed just as value fields such -as \verb@numer@ are. The difference between values and parameterless -methods lies in their definition. The right-hand side of a value is -evaluated when the object is created, and the value does not change -afterwards. A right-hand side of a parameterless method, on the other -hand, is evaluated each time the method is called. The uniform access -of fields and parameterless methods gives increased flexibility for -the implementer of a class. Often, a field in one version of a class -becomes a computed value in the next version. Uniform access ensures -that clients do not have to be rewritten because of that change. - -\paragraph{Abstract Classes} - -Consider the task of writing a class for sets of integer numbers with -two operations, \verb@incl@ and \verb@contains@. \verb@(s incl x)@ -should return a new set which contains the element \verb@x@ togther -with all the elements of set \verb@s@. \verb@(s contains x)@ should -return true if the set \verb@s@ contains the element \verb@x@, and -should return \verb@false@ otherwise. The interface of such sets is -given by: -\begin{verbatim} -abstract class IntSet { - def incl(x: int): IntSet; - def contains(x: int): boolean; -} -\end{verbatim} -\verb@IntSet@ is labeled as an \emph{abstract class}. This has two -consequences. First, abstract classes may have {\em deferred} members -which are declared but which do not have an implementation. In our -case, both \verb@incl@ and \verb@contains@ are such members. Second, -because an abstract class might have unimplemented members, no objects -of that class may be created using \verb@new@. By contrast, an -abstract class may be used as a base class of some other class, which -implements the deferred members. - -\paragraph{Traits.} - -Instead of ``\verb@abstract class@ one also often uses the keyword -\verb@trait@ in Scala. A trait is an abstract class with no state, no -constructor arguments, and no side effects during object -initialization. Since \verb@IntSet@'s fall in this category, one can -alternatively define them as traits: -\begin{verbatim} -trait IntSet { - def incl(x: int): IntSet; - def contains(x: int): boolean; -} -\end{verbatim} -A trait corresponds to an interface in Java, except -that a trait can also define implemented methods. - -\paragraph{Implementing Abstract Classes} - -Let's say, we plan to implement sets as binary trees. There are two -possible forms of trees. A tree for the empty set, and a tree -consisting of an integer and two subtrees. Here are their -implementations. - -\begin{verbatim} -class Empty extends IntSet { - def contains(x: int): boolean = false; - def incl(x: int): IntSet = new NonEmpty(x, new Empty, new Empty); -} -\end{verbatim} - -\begin{verbatim} -class NonEmpty(elem:int, left:IntSet, right:IntSet) extends IntSet { - def contains(x: int): boolean = - if (x < elem) left contains x - else if (x > elem) right contains x - else true; - def incl(x: int): IntSet = - if (x < elem) new NonEmpty(elem, left incl x, right) - else if (x > elem) new NonEmpty(elem, left, right incl x) - else this; -} -\end{verbatim} -Both \verb@Empty@ and \verb@NonEmpty@ extend class -\verb@IntSet@. This implies that types \verb@Empty@ and -\verb@NonEmpty@ conform to type \verb@IntSet@ -- a value of type \verb@Empty@ or \verb@NonEmpty@ may be used wherever a value of type \verb@IntSet@ is required. - -\exercise Write methods \verb@union@ and \verb@intersection@ to form -the union and intersection between two sets. - -\exercise Add a method -\begin{verbatim} -def excl(x: int) -\end{verbatim} -to return the given set without the element \verb@x@. To accomplish this, -it is useful to also implement a test method -\begin{verbatim} -def isEmpty: boolean -\end{verbatim} -for sets. - -\paragraph{Dynamic Binding} - -Object-oriented languages (Scala included) use \emph{dynamic dispatch} -for method invocations. That is, the code invoked for a method call -depends on the run-time type of the object which contains the method. -For example, consider the expression \verb@s contains 7@ where -\verb@s@ is a value of declared type \verb@s: IntSet@. Which code for -\verb@contains@ is executed depends on the type of value of \verb@s@ at run-time. -If it is an \verb@Empty@ value, it is the implementation of \verb@contains@ in class \verb@Empty@ that is executed, and analogously for \verb@NonEmpty@ values. -This behavior is a direct consequence of our substitution model of evaluation. -For instance, -\begin{verbatim} - (new Empty).contains(7) - --> $\rewriteby{by replacing {\sl contains} by its body in class {\sl Empty}}$ - - false -\end{verbatim} -Or, -\begin{verbatim} - new NonEmpty(7, new Empty, new Empty).contains(1) - --> $\rewriteby{by replacing {\sl contains} by its body in class {\sl NonEmpty}}$ - - if (1 < 7) new Empty contains 1 - else if (1 > 7) new Empty contains 1 - else true - --> $\rewriteby{by rewriting the conditional}$ - - new Empty contains 1 - --> $\rewriteby{by replacing {\sl contains} by its body in class {\sl Empty}}$ - - false . -\end{verbatim} - -Dynamic method dispatch is analogous to higher-order function -calls. In both cases, the identity of code to be executed is known -only at run-time. This similarity is not just superficial. Indeed, -Scala represents every function value as an object (see -Section~\ref{sec:funs-are-objects}). - - -\paragraph{Objects} - -In the previous implementation of integer sets, empty sets were -expressed with \verb@new Empty@; so a new object was created every time -an empty set value was required. We could have avoided unnecessary -object creations by defining a value \verb@empty@ once and then using -this value instead of every occurrence of \verb@new Empty@. E.g. -\begin{verbatim} -val empty = new Empty; -\end{verbatim} -One problem with this approach is that a value definition such as the -one above is not a legal top-level definition in Scala; it has to be -part of another class or object. Also, the definition of class -\verb@Empty@ now seems a bit of an overkill -- why define a class of objects, -if we are only interested in a single object of this class? A more -direct approach is to use an {\em object definition}. Here is -a more streamlined alternative definition of the empty set: -\begin{verbatim} -object empty extends IntSet { - def contains(x: int): boolean = false; - - def incl(x: int): IntSet = new NonEmpty(x, empty, empty); -} -\end{verbatim} -The syntax of an object definition follows the syntax of a class -definition; it has an optional extends clause as well as an optional -body. As is the case for classes, the extends clause defines inherited -members of the object whereas the body defines overriding or new -members. However, an object definition defines a single object only; -it is not possible to create other objects with the same structure -using \verb@new@. Therefore, object definitions also lack constructor -parameters, which might be present in class definitions. - -Object definitions can appear anywhere in a Scala program; including -at top-level. Since there is no fixed execution order of top-level -entities in Scala, one might ask exactly when the object defined by an -object definition is created and initialized. The answer is that the -object is created the first time one of its members is accessed. This -strategy is called {\em lazy evaluation}. - -\paragraph{Standard Classes} - -Scala is a pure object-oriented language. This means that every value -in Scala can be regarded as an object. In fact, even primitive types -such as \verb@int@ or \verb@boolean@ are not treated specially. They -are defined as type aliases of Scala classes in module \verb@Predef@: -\begin{verbatim} -type boolean = scala.Boolean; -type int = scala.Int; -type long = scala.Long; -... -\end{verbatim} -For efficiency, the compiler usually represents values of type -\verb@scala.Int@ by 32 bit integers, values of type -\verb@scala.Boolean@ by Java's booleans, etc. But it converts these -specialized representations to objects when required, for instance -when a primitive \verb@int@ value is passed to a function that with a -parameter of type \verb@Object@. Hence, the special representation of -primitive values is just an optimization, it does not change the -meaning of a program. - -Here is a specification of class \verb@Boolean@. -\begin{verbatim} -package scala; -trait Boolean { - def && (def x: Boolean)\=: Boolean; - def || (def x: Boolean)\>: Boolean; - def ! \>: Boolean; - - def == (x: Boolean)\>: Boolean - def != (x: Boolean)\>: Boolean - def < (x: Boolean)\>: Boolean - def > (x: Boolean)\>: Boolean - def <= (x: Boolean)\>: Boolean - def >= (x: Boolean)\>: Boolean -} -\end{verbatim} -Booleans can be defined using only classes and objects, without -reference to a built-in type of booleans or numbers. A possible -implementation of class \verb@Boolean@ is given below. This is not -the actual implementation in the standard Scala library. For -efficiency reasons the standard implementation is built from built-in -booleans. -\begin{verbatim} -package scala; -trait Boolean { - def ifThenElse(def thenpart: Boolean, def elsepart: Boolean) - - def && (def x: Boolean)\=: Boolean = ifThenElse(x, false); - def || (def x: Boolean)\>: Boolean = ifThenElse(true, x); - def ! \>: Boolean = ifThenElse(false, true); - - def == (x: Boolean)\>: Boolean = ifThenElse(x, x.!); - def != (x: Boolean)\>: Boolean = ifThenElse(x.!, x); - def < (x: Boolean)\>: Boolean = ifThenElse(false, x); - def > (x: Boolean)\>: Boolean = ifThenElse(x.!, false); - def <= (x: Boolean)\>: Boolean = ifThenElse(x, true); - def >= (x: Boolean)\>: Boolean = ifThenElse(true, x.!); -} -object True extends Boolean \={ def ifThenElse(def t: Boolean, def e: Boolean) = t } -object False extends Boolean \>{ def ifThenElse(def t: Boolean, def e: Boolean) = e } -\end{verbatim} -Here is a partial specification of class \verb@Int@. - -\begin{verbatim} -package scala; -trait Int extends Long { - def + (that: Double): Double; - def + (that: Float): Float; - def + (that: Long): Long; - def + (that: Int): Int; \=/* analogous for -, *, /, % */ - - def << (cnt: Int): Int; \>/* analogous for >>, >>> */ - - def & (that: Long): Long; - def & (that: Int): Int; \>/* analogous for |, ^ */ - - def == (that: Double): Boolean; - def == (that: Float): Boolean; - def == (that: Long): Boolean; \> /* analogous for !=, <, >, <=, >= */ -} -\end{verbatim} - -Class \verb@Int@ can in principle also be implemented using just -objects and classes, without reference to a built in type of -integers. To see how, we consider a slightly simpler problem, namely -how to implement a type \verb@Nat@ of natural (i.e. non-negative) -numbers. Here is the definition of a trait \verb@Nat@: -\begin{verbatim} -trait Nat { - def isZero: Boolean; - def predecessor: Nat; - def successor: Nat; - def + (that: Nat): Nat; - def - (that: Nat): Nat; -} -\end{verbatim} -To implement the operations of class \verb@Nat@, we define a subobject -\verb@Zero@ and a subclass \verb@Succ@ (for successor). Each number -\verb@N@ is represented as \verb@N@ applications of the \verb@Succ@ -constructor to \verb@Zero@: -\[ -\underbrace{\mbox{\sl new Succ( ... new Succ}}_{\mbox{$N$ times}}\mbox{\sl (Zero) ... )} -\] -The implementation of the \verb@Zero@ object is straightforward: -\begin{verbatim} -object Zero extends Nat { - def isZero: Boolean = true; - def predecessor: Nat = error("negative number"); - def successor: Nat = new Succ(Zero); - def + (that: Nat): Nat = that; - def - (that: Nat): Nat = if (that.isZero) Zero else error("negative number") -} -\end{verbatim} - -The implementation of the predecessor and subtraction functions on -\verb@Zero@ contains a call to the predefined \verb@error@ -function. This function aborts the program with the given error -message. - -Here is the implementation of the successor class: -\begin{verbatim} -class Succ(x: Nat) extends Nat { - def isZero: Boolean = false; - def predecessor: Nat = x; - def successor: Nat = new Succ(this); - def + (that: Nat): Nat = x.+(that.successor); - def - (that: Nat): Nat = x.-(that.predecessor) -} -\end{verbatim} -Note the implementation of method \verb@successor@. To create the -successor of a number, we need to pass the object itself as an -argument to the \verb@Succ@ constructor. The object itself is -referenced by the reserved name \verb@this@. - -The implementations of \verb@+@ and \verb@-@ each contain a recursive -call with the constructor argument as receiver. The recursion will -terminate once the receiver is the \verb@Zero@ object (which is -guaranteed to happen eventually from the way numbers are formed). - -\exercise Write an implementation \verb@Integer@ of integer numbers -The implementation should support all operations of class \verb@Nat@ -while adding two methods -\begin{verbatim} -def isPositive: Boolean -def negate: Integer -\end{verbatim} -The first method should return \verb@true@ if the number is positive. The second method should negate the number. -Do not use any of Scala's standard numeric classes in your -implementation. (Hint: There are two possible ways to implement -\verb@Integer@. One can either make use the existing implementation of -\verb@Nat@, representing an integer as a natural number and a sign. -Or one can generalize the given implementation of \verb@Nat@ to -\verb@Integer@, using the three subclasses \verb@Zero@ for 0, -\verb@Succ@ for positive numbers and \verb@Pred@ for negative numbers.) - - - -\paragraph{Language Elements Introduced In This Chapter} - -\paragraph{Types:} -\begin{verbatim} -Type \= = ... | ident -\end{verbatim} - -Types can now be arbitrary identifiers which represent classes. - -\paragraph{Expressions:} -\begin{verbatim} -Expr \= = ... | Expr `.' ident | new Expr | this -\end{verbatim} - -An expression can now be an object creation, or -a selection \verb@E.m@ of a member \verb@m@ -from an object-valued expression \verb@E@, or it can be the reserved name \verb@this@. - -\paragraph{Definitions and Declarations:} -\begin{verbatim} -Def \= = \=FunDef | ValDef | ClassDef | TraitDef | ObjectDef -ClassDef \> = \>[abstract] class ident [`(' [Parameters] `)'] - \> \>[extends Expr] [`{' {TemplateDef} `}'] -TraitDef \> = \>trait ident [extends Expr] [`{' {TemplateDef} `}'] -ObjectDef \> = \>object ident [extends Expr] [`{' {ObjectDef} `}'] -TemplateDef \> = \>[Modifier] (Def | Dcl) -ObjectDef \> = \>[Modifier] Def -Modifier \> = \>private | override -Dcl \> = \>FunDcl | ValDcl -FunDcl \> = \>def ident {`(' [Parameters] `)'} `:' Type -ValDcl \> = \>val ident `:' Type -\end{verbatim} - -A definition can now be a class, trait or object definition such as -\begin{verbatim} -class C(params) extends B { defs } -trait T extends B { defs } -object O extends B { defs } -\end{verbatim} -The definitions \verb@defs@ in a class, trait or object may be -preceded by modifiers \verb@private@ or \verb@override@. - -Abstract classes and traits may also contain declarations. These -introduce {\em deferred} functions or values with their types, but do -not give an implementation. Deferred members have to be implemented in -subclasses before objects of an abstract class or trait can be created. - -\chapter{Case Classes and Pattern Matching} - -Say, we want to write an interpreter for arithmetic expressions. To -keep things simple initially, we restrict ourselves to just numbers -and \verb@+@ operations. Such expressions can be represented as a class hierarchy, with an abstract base class \verb@Expr@ as the root, and two subclasses \verb@Number@ and -\verb@Sum@. Then, an expression \verb@1 + (3 + 7)@ would be represented as -\begin{verbatim} -new Sum(new Number(1), new Sum(new Number(3), new Number(7))) -\end{verbatim} -Now, an evaluator of an expression like this needs to know of what -form it is (either \verb@Sum@ or \verb@Number@) and also needs to -access the components of the expression. The following -implementation provides all necessary methods. -\begin{verbatim} -abstract class Expr { - def isNumber: boolean; - def isSum: boolean; - def numValue: int; - def leftOp: Expr; - def rightOp: Expr; -} -\end{verbatim} -\begin{verbatim} -class Number(n: int) extends Expr { - def isNumber: boolean = true; - def isSum: boolean = false; - def numValue: int = n; - def leftOp: Expr = error("Number.leftOp"); - def rightOp: Expr = error("Number.rightOp"); -} -\end{verbatim} -\begin{verbatim} -class Sum(e1: Expr, e2: Expr) extends Expr { - def isNumber: boolean = false; - def isSum: boolean = true; - def numValue: int = error("Sum.numValue"); - def leftOp: Expr = e1; - def rightOp: Expr = e2;} -\end{verbatim} -With these classification and access methods, writing an evaluator function is simple: -\begin{verbatim} -def eval(e: Expr): int = { - if (e.isNumber) e.numValue - else if (e.isSum) eval(e.leftOp) + eval(e.rightOp) - else error("unrecognized expression kind") -} -\end{verbatim} -However, defining all these methods in classes \verb@Sum@ and -\verb@Number@ is rather tedious. Furthermore, the problem becomes worse -when we want to add new forms of expressions. For instance, consider -adding a new expression form -\verb@Prod@ for products. Not only do we have to implement a new class \verb@Prod@, with all previous classification and access methods; we also have to introduce a -new abstract method \verb@isProduct@ in class \verb@Expr@ and -implement that method in subclasses \verb@Number@, \verb@Sum@, and -\verb@Prod@. Having to modify existing code when a system grows is always problematic, since it introduces versioning and maintenance problems. - -The promise of object-oriented programming is that such modifications -should be unnecessary, because they can be avoided by re-using -existing, unmodified code through inheritance. Indeed, a more -object-oriented decomposition of our problem solves the problem. The -idea is to make the ``high-level'' operation \verb@eval@ a method of -each expression class, instead of implementing it as a function -outside the expression class hierarchy, as we have done -before. Because \verb@eval@ is now a member of all expression nodes, -all classification and access methods become superfluous, and the implementation is simplified considerably: -\begin{verbatim} -abstract class Expr { - def eval: int; -} -class Number(n: int) extends Expr { - def eval: int = n; -} -class Sum(e1: Expr, e2: Expr) extends Expr { - def eval: int = e1.eval + e2.eval; -} -\end{verbatim} -Furthermore, adding a new \verb@Prod@ class does not entail any changes to existing code: -\begin{verbatim} -class Prod(e1: Expr, e2: Expr) extends Expr { - def eval: int = e1.eval * e2.eval; -} -\end{verbatim} - -The conclusion we can draw from this example is that object-oriented -decomposition is the technique of choice for constructing systems that -should be extensible with new types of data. But there is also another -possible way we might want to extend the expression example. We might -want to add new {\em operations} on expressions. For instance, we might -want to add an operation that pretty-prints an expression tree to standard output. - -If we have defined all classification and access methods, such an -operation can easily be written as an external function. Here is an -implementation: -\begin{verbatim} -def print(e: Expr): unit = - if (e.isNumber) System.out.print(e.numValue) - else if (e.isSum) { - System.out.print("("); - print(e.leftOp); - System.out.print("+"); - print(e.rightOp); - System.out.print(")"); - } else error("unrecognized expression kind"); -\end{verbatim} -However, if we had opted for an object-oriented decomposition of -expressions, we would need to add a new \verb@print@ method -to each class: -\begin{verbatim} -abstract class Expr { - def eval: int; - def print: unit; -} -class Number(n: int) extends Expr { - def eval: int = n; - def print: unit = System.out.print(n); -} -class Sum(e1: Expr, e2: Expr) extends Expr { - def eval: int = e1.eval + e2.eval; - def print: unit = { - System.out.print("("); - print(e1); - System.out.print("+"); - print(e2); - System.out.print(")"); -} -\end{verbatim} -Hence, classical object-oriented decomposition requires modification -of all existing classes when a system is extended with new operations. - -As yet another way we might want to extend the interpreter, consider -expression simplification. For instance, we might want to write a -function which rewrites expressions of the form -\verb@a * b + a * c@ to \verb@a * (b + c)@. This operation requires inspection of -more than a single node of the expression tree at the same -time. Hence, it cannot be implemented by a method in each expression -kind, unless that method can also inspect other nodes. So we are -forced to have classification and access methods in this case. This -seems to bring us back to square one, with all the problems of -verbosity and extensibility. - -Taking a closer look, one observers that the only purpose of the -classification and access functions is to {\em reverse} the data -construction process. They let us determine, first, which sub-class -of an abstract base class was used and, second, what were the -constructor arguments. Since this situation is quite common, Scala has -a way to automate it with case classes. - -\paragraph{Case Classes.} -A {\em case class} is defined like a normal class, except that the definition -is prefixed with the modifier \verb@case@. For instance, the definitions -\begin{verbatim} -abstract class Expr; -case class Number(n: int) extends Expr; -case class Sum(e1: Expr, e2: Expr) extends Expr; -\end{verbatim} -introduce \verb@Number@ and \verb@Sum@ as case classes. -The \verb@case@ modifier in front of a class definition has the following effects. -\begin{enumerate} -\item Case classes implicitly come with a constructor function, with the same name as the class. In our example, the two functions -\begin{verbatim} -def Number(n: int) = new Number(n); -def Sum(e1: Expr, e2: Expr) = new Sum(e1, e2); -\end{verbatim} -would be added. Hence, one can now construct expression trees a bit more concisely, as in -\begin{verbatim} -Sum(Sum(Number(1), Number(2)), Number(3)) -\end{verbatim} -\item Case classes implicity come with implementations of methods -\verb@toString@, \verb@equals@ and \verb@hashCode@, which override the -methods with the same name in class \verb@Object@. The implementation -of these methods takes in each case the structure of a member of a -case class into account. The \verb@toString@ method represents an -expression tree the way it was constructed. So, -\begin{verbatim} -Sum(Sum(Number(1), Number(2)), Number(3)) -\end{verbatim} -would be converted to exactly that string, whereas he default -implementation in class \verb@Object@ would return a string consisting -of the outermost constructor name \verb@Sum@ and a number. The -\verb@equals@ methods treats two case members of a case class as equal -if they have been constructed with the same constructor and with -arguments which are themselves pairwise equal. This also affects the -implementation of \verb@==@ and \verb@!=@, which are implemented in -terms of \verb@equals@ in Scala. So, -\begin{verbatim} -Sum(Number(1), Number(2)) == Sum(Number(1), Number(2)) -\end{verbatim} -will yield \verb@true@. If \verb@Sum@ or \verb@Number@ were not case -classes, the same expression would be \verb@false@, since the standard -implementation of \verb@equals@ in class \verb@Object@ always treats -objects created by different constructor calls as being different. -The \verb@hashCode@ method follows the same principle as other two -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 \verb@hashCode@ does. -\item -Case classes implicity come with nullary accessor methods which -retrieve the constructor arguments. -In our example, \verb@Number@ would obtain an accessor method -\begin{verbatim} -def n: int -\end{verbatim} -which returns the constructor parameter \verb@n@, whereas \verb@Sum@ would obtain two accessor methods -\begin{verbatim} -def e1: Expr, e2: Expr; -\end{verbatim} -Hence, if for a value \verb@s@ of type \verb@Sum@, say, one can now -write \verb@s.e1@, to access the left operand. However, for a value -\verb@e@ of type \verb@Expr@, the term \verb@e.e1@ would be illegal -since \verb@e1@ is defined in \verb@Sum@; it is not a member of the -base class \verb@Expr@. -So, how do we determine the constructor and access constructor -arguments for values whose static type is the base class \verb@Expr@? -This is solved by the fourth and final particularity of case classes. -\item -Case classes allow the constructions of {\em patterns} which refer to -the case class constructor. -\end{enumerate} - -\paragraph{Pattern Matching.} - -Pattern matching is a generalization of C or Java's \verb@switch@ -statement to class hierarchies. Instead of a \verb@switch@ statement, -there is a standard method \verb@match@, which is defined in Scala's -root class \verb@Any@, and therefore is available for all objects. -The \verb@match@ method takes as argument a number of cases. -For instance, here is an implementation of \verb@eval@ using -pattern matching. -\begin{verbatim} -def eval(e: Expr): int = e match { - case Number(x) => x - case Sum(l, r) => eval(l) + eval(r) -} -\end{verbatim} -In this example, there are two cases. Each case associates a pattern -with an expression. Patterns are matched against the selector -values \verb@e@. The first pattern in our example, -\verb@Number(n)@, matches all values of the form \verb@Number(v)@, -where \verb@v@ is an arbitrary value. In that case, the {\em pattern -variable} \verb@n@ is bound to the value \verb@v@. Similarly, the -pattern \verb@Sum(l, r)@ matches all selector values of form -\verb@Sum(v$_1$, v$_2$)@ and binds the pattern variables \verb@l@ and \verb@r@ -to \verb@v$_1$@ and \verb@v$_2$@, respectively. - -In general, patterns are built from -\begin{itemize} -\item Case class constructors, e.g. \verb@Number@, \verb@Sum@, whose arguments - are again patterns, -\item pattern variables, e.g. \verb@n@, \verb@e1@, \verb@e2@, -\item the ``wildcard'' pattern \verb@_@, -\item constants, e.g. \verb@1@, \verb@true@, "abc", \verb@MAXINT@. -\end{itemize} -Pattern variables always start with a lower-case letter, so that they -can be distinguished from constant identifiers, which start with an -upper case letter. The only exceptions to that rule are the reserved -words \verb@null@, \verb@true@, \verb@false@, which are treated as constants. -Each variable name may occur only once in a pattern. For instance, -\verb@Sum(x, x)@ would be illegal as a pattern, since \verb@x@ occurs -twice in it. - -\paragraph{Meaning of Pattern Matching.} -A pattern matching expression -\begin{verbatim} -e.match { case p$_1$ => e$_1$ ... case p$_n$ => e$_n$ } -\end{verbatim} -matches the patterns $p_1 \commadots p_n$ in the order they -are written against the selector value \verb@e@. -\begin{itemize} -\item -A constructor pattern $C(p_1 \commadots p_n)$ matches all values that -are of type \verb@C@ (or a subtype thereof) and that have been constructed with -\verb@C@-arguments matching patterns $p_1 \commadots p_n$. -\item -A variable pattern \verb@x@ matches any value and binds the variable -name to that value. -\item -The wildcard pattern `\verb@_@' matches any value but does not bind a name to that value. -\item A constant pattern \verb@C@ matches a value which is -equal (in terms of \verb@==@) to \verb@C@. -\end{itemize} -The pattern matching expression rewrites to the right-hand-side of the -first case whose pattern matches the selector value. References to -pattern variables are replaced by corresponding constructor arguments. -If none of the patterns matches, the pattern matching expression is -aborted with a \verb@MatchError@ exception. - -\example Our substitution model of program evaluation extends quite naturally to pattern matching, For instance, here is how \verb@eval@ applied to a simple expression is re-written: -\begin{verbatim} - \= eval(Sum(Number(1), Number(2))) - --> \> $\mbox{\tab\tab\rm(by rewriting the application)}$ - - \> Sum(Number(1), Number(2)) match { - \> case Number(n) => n - \> case Sum(e1, e2) => eval(e1) + eval(e2) - \> } - --> \> $\mbox{\tab\tab\rm(by rewriting the pattern match)}$ - - \> eval(Number(1)) + eval(Number(2)) - --> \> $\mbox{\tab\tab\rm(by rewriting the first application)}$ - - \> Number(1) match { - \> case Number(n) => n - \> case Sum(e1, e2) => eval(e1) + eval(e2) - \> } + eval(Number(2)) - --> \> $\mbox{\tab\tab\rm(by rewriting the pattern match)}$ - - \> 1 + eval(Number(2)) - -->$^*$ \> 1 + 2 -> 3 -\end{verbatim} - -\paragraph{Pattern Matching and Methods.} In the previous example, we have used pattern -matching in a function which was defined outside the class hierarchy -over which it matches. Of course, it is also possible to define a -pattern matching function in that class hierarchy itself. For -instance, we could have defined -\verb@eval@ is a method of the base class \verb@Expr@, and still have used pattern matching in its implementation: -\begin{verbatim} -abstract class Expr { - def eval: int = this match { - case Number(n) => n - case Sum(e1, e2) => e1.eval + e2.eval - } -} -\end{verbatim} - -\exercise -Consider the following three classes representing trees of integers. -These classes can be seen as an alternative representation of \verb@IntSet@: -\begin{verbatim} -trait IntTree; -case class Empty extends IntTree; -case class Node(elem: int, left: IntTree, right: IntTree) extends IntTree; -\end{verbatim} -Complete the following implementations of function \verb@contains@ and \verb@insert@ for -\verb@IntTree@'s. -\begin{verbatim} -def contains(t: IntTree, v: int): boolean = t match { ... - ... -} -def insert(t: IntTree, v: int): IntTree = t match { ... - ... -} -\end{verbatim} - -\subsection*{Tuples} - -Sometimes, a function needs to return more than one result. For -instance, take the function \verb@divmod@ which returns the quotient -and rest of two given integer arguments. Of course, one can -define a class to hold the two results of \verb@divmod@, as in: -\begin{verbatim} -case class TwoInts(first: int, second: int); - -def divmod(x: int, y: int): TwoInts = new TwoInts(x / y, x % y) -\end{verbatim} -However, having to define a new class for every possible pair of -result types is very tedious. It should also be unneccessary because -all such classes have exactly the same structure. In Scala, the -repetition can be avoided by defining a {\em generic class}: -\begin{verbatim} -case class Pair[+a, +b](first: a, second: b); - -def divmod(x: int, y: int): Pair[int, int] = new Pair[Int, Int](x / y, x % y) -\end{verbatim} -In this example, \verb@[a, b]@ are {\em type parameters} of class -\verb@Pair@. In a \verb@Pair@ type, these parameters are replaced by -concrete types. For instance, \verb@Pair[int, String]@ represents the -type of pairs with \verb@int@ and \verb@String@ elements. - -Type arguments can be omitted in constructors, if the correct type can -be inferred from the other constructor arguments or the constructor's -expected result type. In our example, we could have omitted the type -arguments in the body of \verb@divmod@, because they can be deduced -from the two value parameters of type \verb@int@: -\begin{verbatim} -def divmod(x: int, y: int): Pair[int, int] = new Pair(x / y, x % y) -\end{verbatim} -Type parameters are never used in patterns. For instance, here is an -expression in which \verb@divmod@'s result is decomposed: -\begin{verbatim} -divmod(x, y) match { - case Pair(n, d) => System.out.println("quotient: " + n + ", rest: " + d); -} -\end{verbatim} -The type parameters in class \verb@Pair@ are each prefixed by a -\verb@+@ sign. This indicates that \verb@Pair@s are {\em -covariant}. That is, if types \verb@T$_1$@ and \verb@T$_2$@ are -subtypes of types \verb@S$_1$@ and \verb@S$_2$@, then -\verb@Pair[T$_1$, T$_2$]@ is a subtype of -\verb@Pair[S$_1$, S$_2$]@. For instance, \verb@Pair[String, int]@ is a -subtype of \verb@Pair[Object, long]@. If the \verb@+@-annotation was -missing, the type constructor would be treated as being -non-variant. That is, pairs with different element types would never -be in a subtype relation. -Besides, \verb@+@, there is also a prefix -\verb@-@ for contra-variant type constructors. -The precise rules that -for variance annotations are given in Chapter~\ref{sec:variance}. - -The idea of pairs is generalized in Scala to tuples of greater arity. -There is a predefined case class \verb@Tuple$_n$@ for every \verb@n@ -from \verb@2@ to \verb@9@ in Scala's standard library. The -definitions all follow the template -\begin{verbatim} -case class Tuple$_n$[+a$_1$, ..., +a$_n$](_1: a$_1$, ..., _n: a$_n$); -\end{verbatim} -Class \verb@Pair@ (as well as class \verb@Triple@) are also -predefined, but not as classes of their own. Instead -\verb@Pair@ is an alias of \verb@Tuple2@ and \verb@Triple@ is an -alias of \verb@Tuple3@. - -\chapter{Lists} - -The list is an important data structure in many Scala programs. -A list with elements \verb@x$_1$, ..., x$_n$@ is written -\verb@List(x$_1$, ..., x$_n$)@. Examples are: -\begin{verbatim} -val fruit \= = List("apples", "oranges", "pears"); -val nums \> = List(1, 2, 3, 4); -val diag3 \> = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1)); -val empty \> = List(); -\end{verbatim} -Lists are similar to arrays in languages such as C or Java, but there -are also three important differences. First, lists are immutable. That -is, elements of a list can not be changed by assignment. Second, -lists have a recursive structure, whereas arrays are flat. Third, -lists support a much richer set of operations than arrays usually do. - -\paragraph{The list type.} -Like arrays, lists are {\em homogeneous}. That is, the elements of a -list all have the same type. The type of a list with elements of type -\verb@T@ is written \verb@List[T]@. (Compare to \verb@[]T@ for the -type of arrays of type \verb@T@ in C or Java.). Therefore, the -definitions of list values above can be annotated with types as -follows. -\begin{verbatim} -val fruit \= : List[String] \= = List("apples", "oranges", "pears"); -val nums \> : List[int] \> = List(1, 2, 3, 4); -val diag3 \> : List[List[int]] \> = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1)); -val empty \> : List[int] \> = List(); -\end{verbatim} - -\paragraph{List constructors.} -All lists are built from two more fundamental constructors, \verb@Nil@ -and \verb@::@ (pronounced ``cons''). \verb@Nil@ represents an empty -list. The infix operator \verb@::@ expresses list extension. That is, -\verb@x :: xs@ represents a list whose first element is \verb@x@, -which is followed by (the elements of) list \verb@xs@. Hence, the -list values above could also have been defined as follows (in fact -their previous definition is simply syntactic sugar for the definitions below). -\begin{verbatim} -val fruit \= = "apples" :: ("oranges" :: ("pears" :: Nil)); -val nums \> = 1 :: (2 :: (3 :: (4 :: Nil))); -val diag3 \> = \= (1 :: (0 :: (0 :: Nil))) :: - \> \> (0 :: (1 :: (0 :: Nil))) :: - \> \> (0 :: (0 :: (1 :: Nil))) :: Nil; -val empty \> = Nil; -\end{verbatim} -The `\verb@::@' operation associates to the right: \verb@A :: B :: C@ is -interpreted as \verb@A :: (B :: C)@. Therefore, we can drop the -parentheses in the definitions above. For instance, we can write -shorter -\begin{verbatim} -val nums = 1 :: 2 :: 3 :: 4 :: Nil; -\end{verbatim} - -\paragraph{Basic operations on lists.} -All operations on lists can be expressed in terms of the following three: - -\begin{tabular}{ll} -\verb@head@ & returns the first element of a list,\\ -\verb@tail@ & returns the list consisting of all elements except the\\ -first element, -\verb@isEmpty@ & returns \verb@true@ iff the list is empty -\end{tabular} - -These operations are defined as methods of list objects. So we invoke -them by selecting from the list that's operated on. Examples: -\begin{verbatim} -empty.isEmpty \= = true -fruit.isEmpty \> = false -fruit.head \> = "apples" -fruit.tail.head \> = "oranges" -diag3.head \> = List(1, 0, 0) -\end{verbatim} -Both \verb@head@ and \verb@tail@ are only defined for non-empty lists. -When selected from an empty list, they cause an error instead. - -As an example of how lists can be processed, consider sorting the -elements of a list of numbers into ascending order. One simple way to -do so is {\em insertion sort}, which works as follows: To sort a -non-empty list with first element \verb@x@ and rest \verb@xs@, sort -the remainder \verb@xs@ and insert the element \verb@x@ at the right -position in the result. Sorting an empty list will of course yield the -empty list. Expressed as Scala code: -\begin{verbatim} -def isort(xs: List[int]): List[int] = - if (xs.isEmpty) Nil - else insert(xs.head, isort(xs.tail)) -\end{verbatim} - -\exercise Provide an implementation of the missing function -\verb@insert@. - -\paragraph{List patterns.} In fact, \verb@::@ is -defined defined as a case class in Scala's standard library. Hence, it -is possible to decompose lists by pattern matching, using patterns -composed from the \verb@Nil@ and \verb@::@ constructors. For instance, -\verb@isort@ can be written alternatively as follows. -\begin{verbatim} -def isort(xs: List[int]): List[int] = xs match { - case List() => List() - case x :: xs1 => insert(x, isort(xs1)) -} -\end{verbatim} -where -\begin{verbatim} -def insert(x: int, xs: List[int]): List[int] = xs match { - case List() => List(x) - case y :: ys => if (x <= y) x :: xs else y :: insert(x, ys) -} -\end{verbatim} - -\paragraph{Polymorphic functions.} Consider the problem of writing a - function \verb@concat@, which takes a list of element lists as - arguments. The result of \verb@concat@ should be the concatenation of all - element lists into a single list. - -When trying to define such a function, we observe that we need to give -a type for the list elements: -\begin{verbatim} -def concat(xss: List[List[ ?? ]]): List[ ?? ] = ... -\end{verbatim} -Clearly, one could replace \verb@??@ by \verb@int@, say, to obtain a -function \verb@concat@ that works on lists of lists of integers. But then the -same function could not be applied to other kinds of lists. This is a -pity, since clearly the same algorithm of list concatenation can work -for lists of any element type. Parameterization lets us generalize -from a specific instance of a problem to a more general one. So far, -we have used parameterization only for values, but it is available -also for types. To arrive at a general version of \verb@concat@, we -equip it with a type parameter. -\begin{verbatim} -def concat[a](xs: List[List[a]]): List[a] = xs match { - case List() => xs - case List() :: yss => concat[a](yss) - case (x :: xs) :: yss => x :: concat[a](xs :: yss) -} -\end{verbatim} -Type parameters are arbitrary names; they are enclosed in brackets -instead of parentheses, so that they can be easily distinguished from -value parameters. Functions like \verb@concat@ that take type -parameters are called {\em polymorphic}. The term comes from the -Greek, where it means ``having many forms''. - -To apply \verb@concat@, we pass type parameters as well as value -parameters to it. For instance, -\begin{verbatim} -val diag3 = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1)); -concat[int](diag3) -\end{verbatim} -yields \verb@List(1, 0, 0, 0, 1, 0, 0, 0, 1)@. - -\paragraph{Local Type Inference.} -Passing type parameters such as \verb@[int]@ all the time can become -tedious in applications where polymorphic functions are used a -lot. Quite often, the information in a type parameter is redundant, -because the correct parameter type can also be determined by -inspecting the function's value parameters or expected result type. -Taking \verb@concat[int](diag3)@ function as an example, we know that -its value parameter is of type \verb@List[List[int]]@, so we can -deduce that the type parameter must be \verb@int@. Scala has a -fairly powerful type inferencer which allows one to omit type -parameters to polymorphic functions and constructors in situations -like these. In the example above, the \verb@int@ type parameter would -have been inferred if it was not given explicitly. In fact, the same -principle applies in the definition of the value \verb@diag3@. -Here, type parameters have been inferred for the four calls of -\verb@List@. - -\paragraph{Definition of class \verb@List@} - -Lists are not built in in Scala; they are defined by an abstract class -\verb@List@, which comes with two subclasses for \verb@::@ and \verb@Nil@. -In the following we present a tour through class \verb@List@. -\begin{verbatim} -package scala; -abstract class List[+a] { -\end{verbatim} -\verb@List@ is an abstract class, so one cannot define elements by -calling the empty \verb@List@ constructor (e.g. by -\verb@new List@). The class has a type parameter \verb@a@. It is -co-variant in this parameter, which means that -\verb@List[S] <: List[T]@ for all types \verb@S@ and \verb@T@ such that -\verb@S <: T@. The class is situated in the package -\verb@scala@. This is a package containing the most important standard -classes of Scala. \verb@List@ defines a number of methods, which are -explained in the following. - -First, there are the three basic functions \verb@isEmpty@, -\verb@head@, \verb@tail@. Their implementation in terms of pattern -matching is straightforward: -\begin{verbatim} -def isEmpty: boolean = match { - case Nil => true - case x :: xs => false -} -def head: a = match { - case Nil => error("Nil.head") - case x :: xs => x -} -def tail: List[a] = match { - case Nil => error("Nil.tail") - case x :: xs => x -} -\end{verbatim} - -The next function computes the length of a list. -\begin{verbatim} -def length = match { - case Nil => 0 - case x :: xs => 1 + xs.length -} -\end{verbatim} - -\exercise Design a tail-recursive version of \verb@length@. - -The next two functions are the complements of \verb@head@ and -\verb@tail@. -\begin{verbatim} -def last: a; -def init: List[a]; -\end{verbatim} -\verb@xs.last@ returns the last element of list \verb@xs@, whereas -\verb@xs.init@ returns all elements of \verb@xs@ except the last. -Both functions have to traverse the entire list, and are thus less -efficient than their \verb@head@ and \verb@tail@ analogues. -Here is the implementation of \verb@last@. -\begin{verbatim} -def last: a = match { - case Nil \==> error("Nil.last") - case x :: Nil \>=> x - case x :: xs \>=> xs.last -} -\end{verbatim} -The implementation of \verb@init@ is analogous. - -The next three functions return a prefix of the list, or a suffix, or -both. -\begin{verbatim} -def take(n: int): List[a] = - if (n == 0 || isEmpty) Nil else head :: tail.take(n-1); - -def drop(n: int): List[a] = - if (n == 0 || isEmpty) this else tail.drop(n-1); - -def split(n: int): Pair[List[a], List[a]] = - if (n == 0 || isEmpty) Pair(Nil, this) - else tail.split(n - 1) match { case Pair(xs, ys) => (head :: xs, ys) } -\end{verbatim} -\verb@(xs take n)@ returns the first \verb@n@ elements of list -\verb@xs@, or the whole list, if its length is smaller than \verb@n@. -\verb@(xs drop n)@ returns all elements of \verb@xs@ except the -\verb@n@ first ones. Finally, \verb@(xs split n)@ returns a pair -consisting of the lists resulting from \verb@xs take n@ and -\verb@xs drop n@, but the call is more efficient than performing the -two calls separately. - -The next function returns an element at a given index in a list. -It is thus analogous to array subscripting. Indices start at 0. -\begin{verbatim} -def at(n: int): a = drop(n).head; -\end{verbatim} - -With \verb@take@ and \verb@drop@, we can extract sublists consisting -of consecutive elements of the original list. To extract the sublist -$xs_m \commadots xs_{n-1}$ of a list \verb@xs@, use: - -\begin{verbatim} -xs.drop(m).take(n - m) -\end{verbatim} - -The next function combines two lists into a list of pairs. -Given two lists -\begin{verbatim} -xs = List(x$_1$, ..., x$_n$) $\mbox{\rm, and}$ -ys = List(y$_1$, ..., y$_n$) , -\end{verbatim} -\verb@xs zip ys@ constructs the list \verb@Pair(x$_1$, y$_1$), ..., Pair(x$_n$, y$_n$)@. -If the two lists have different lengths, the longer one of the two is -truncated. Here is the definition of \verb@zip@ -- note that it is a -polymorphic method. -\begin{verbatim} -def zip[b](that: List[b]): List[Pair[a,b]] = - if (this.isEmpty || that.isEmpty) Nil - else Pair(this.head, that.head) :: (this.tail zip that.tail); -\end{verbatim} - -Like any infix operator, \verb@::@ -is also implemented as a method of an object. In this case, the object -is the list that is extended. This is possible, because operators -ending with a `\verb@:@' character are treated specially in Scala. -All such operators are treated as methods of their right operand. E.g., -\begin{verbatim} - x :: y = y.::(x) \=$\mbox{\rm whereas}$ x + y = x.+(y) -\end{verbatim} -Note, however, that operands of a binary operation are in each case -evaluated from left to right. So, if \verb@D@ and \verb@E@ are -expressions with possible side-effects, \verb@D :: E@ is translated to -\verb@{val x = D; E.::(x)}@ in order to maintain the left-to-right -order of operand evaluation. - -Another difference between operators ending in a `\verb@:@' and other -operators concerns their associativity. Operators ending in -`\verb@:@' are right-associative, whereas other operators are -left-associative. E.g., -\begin{verbatim} - x :: y :: z = x :: (y :: z) \=$\mbox{\rm whereas}$ x + y + z = (x + y) + z -\end{verbatim} -The definition of \verb@::@ as a method in -class \verb@List@ is as follows: -\begin{verbatim} -def ::[b >: a](x: b): List[b] = new scala.::(x, this); -\end{verbatim} -Note that \verb@::@ is defined for all elements \verb@x@ of type -\verb@B@ and lists of type \verb@List[A]@ such that the type \verb@B@ -of \verb@x@ is a supertype of the list's element type \verb@A@. The result -is in this case a list of \verb@B@'s. This -is expressed by the type parameter \verb@b@ with lower bound \verb@a@ -in the signature of \verb@::@. - -An operation similar to \verb@::@ is list concatenation, written -`\verb@:::@'. The result of \verb@(xs ::: ys)@ is a list consisting of -all elements of \verb@xs@, followed by all elements of \verb@ys@. -Because it ends in a colon, \verb@:::@ is right-associative and is -considered as a method of its right-hand operand. Therefore, -\begin{verbatim} -xs ::: ys ::: zs \= = xs ::: (ys ::: zs) - \> = zs.:::(ys).:::(xs) -\end{verbatim} -Here is the implementation of the \verb@:::@ method: -\begin{verbatim} - def :::[b >: a](prefix: List[b]): List[b] = prefix match { - case Nil => this - case p :: ps => this.:::(ps).::(p) - } -\end{verbatim} - -\paragraph{Example: Reverse.} As another example of how to program with -lists consider a list reversal. There is a method \verb@reverse@ in -\verb@List@ to that effect, but let's implement it as a function -outside the class. Here is a possible implementation of -\verb@reverse@: -\begin{verbatim} -def reverse[a](xs: List[a]): List[a] = xs match { - case List() => List() - case x :: xs => reverse(xs) ::: List(x) -} -\end{verbatim} -The implementation is quite simple. However, it is not very efficient. -Indeed, one concatenation is executed for every element in the -list. List concatenation takes time proportional to the length -of its first operand. Therefore, the complexity of \verb@reverse(xs)@ is -\[ -n + (n - 1) + ... + 1 = n(n+1)/2 -\] -where $n$ is the length of \verb@xs@. Can \verb@reverse@ be -implemented more efficiently? We will see later that there is exists -another implementation which has only linear complexity. - -\paragraph{Example: Merge sort.} -The insertion sort presented earlier in this chapter is simple to -formulate, but also not very efficient. It's average complexity is -proportional to the square of the length of the input list. We now -design a program to sort the elements of a list which is more -efficient than insertion sort. A good algorithm for this is {\em merge -sort}, which works as follows. - -First, if the list has zero or one elements, it is already sorted, so -one returns the list unchanged. Longer lists are split into two -sub-lists, each containing about half the elements of the original -list. Each sub-list is sorted by a recursive call to the sort -function, and the resulting two sorted lists are then combined in a -merge operation. - -For a general implementation of merge sort, we still have to specify -the type of list elements to be sorted, as well as the function to be -used for the comparison of elements. We obtain a function of maximal -generality by passing these two items as parameters. This leads to the -following implementation. -\begin{verbatim} -def msort[a](less: (a, a) => boolean)(xs: List[a]): List[a] = { - val n = xs.length/2; - if (n == 0) xs - else { - def merge(xs1: List[a], xs2: List[a]): List[a] = - if (xs1.isEmpty) xs2 - else if (xs2.isEmpty) xs1 - else if (less(xs1.head, xs2.head)) xs1.head :: merge(xs1.tail, xs2) - else xs2.head :: merge(xs1, xs2.tail); - - merge(msort(less)(xs take n), msort(less)(xs drop n)) - } -} -\end{verbatim} -The complexity of \verb@msort@ is $O(N;log(N))$, where $N$ is the -length of the input list. To see why, note that splitting a list in -two and merging two sorted lists each take time proportional to the -length of the argument list(s). Each recursive call of \verb@msort@ -halves the number of elements in its input, so there are $O(log(N))$ -consecutive recursive calls until the base case of lists of length 1 -is reached. However, for longer lists each call spawns off two -further calls. Adding everything up we obtain that at each of the -$O(log(N))$ call levels, every element of the original lists takes -part in one split operation and in one merge operation. Hence, every -call level has a total cost proportional to $O(N)$. Since there are -$O(log(N))$ call levels, we obtain an overall cost of -$O(N;log(N))$. That cost does not depend on the initial distribution -of elements in the list, so the worst case cost is the same as the -average case cost. This makes merge sort an attractive algorithm for -sorting lists. - -Here is an example how \verb@msort@ is used. -\begin{verbatim} -def iless(x: int, y: int) = x < y -msort(iless)(List(5, 7, 1, 3)) -\end{verbatim} -The definition of \verb@msort@ is curried, to make it easy to specialize it with particular -comparison functions. For instance, -\begin{verbatim} - -val intSort = msort(iless) -val reverseSort = msort(x: int, y: int => x > y) -\end{verbatim} - -\section*{Higher-Order Methods} - -\chapter{Computing with Streams} - -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 -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 -and powerful substitution model for functional computation is no -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 -a function \verb@f(t)@ with a time parameter \verb@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 -list. So, a mutabel variable \verb@var x: T@ gets replaced by an -immutable value \verb@val x: List[T]@. In a sense, we trade space for -time -- the different values of the variable now all exit concurrently -as different elements of the list. One advantage of the list-based -view is that we can ``time-travel'', i.e. view several successive -values of the variable at the same time. Another advantage is that we -can make use of the powerful library of list processing functions, -which often simplifies computation. For instance, consider the way -imperative way to compute the sum of all prime numbers in an interval: -\begin{verbatim} -def sumPrimes(start: int, end: int): int = { - var i = start; - var acc = 0; - while (i < end) { - if (isPrime(i)) acc = acc + i; - i = i + 1; - } - acc -} -\end{verbatim} -Note that the variable \verb@i@ ``steps through'' all values of the interval -\verb@[start .. end-1]@. -%\es\bs -A more functional way is to represent the list of values of variable \verb@i@ directly as \verb@range(start, end)@. Then the function can be rewritten as follows. -\begin{verbatim} -def sumPrimes(start: int, end: int) = - sum(range(start, end) filter isPrime); -\end{verbatim} - -No contest which program is shorter and clearer! However, the -functional program is also considerably less efficient since it -constructs a list of all numbers in the interval, and then another one -for the prime numbers. Even worse from an efficiency point of view is -the following example: - -To find the second prime number between \verb@1000@ and \verb@10000@: -\begin{verbatim} - range(1000, 10000) filter isPrime at 1 -\end{verbatim} -Here, the list of all numbers between \verb@1000@ and \verb@10000@ is -constructed. But most of that list is never inspected! - -However, we can obtain efficient execution for examples like these by -a trick: -\begin{quote} -%\red - Avoid computing the tail of a sequence unless that tail is actually - necessary for the computation. -\end{quote} -We define a new class for such sequences, which is called \verb@Stream@. - -Streams are created using the constant \verb@empty@ and the constructor \verb@cons@, -which are both defined in module \verb@scala.Stream@. For instance, the following -expression constructs a stream with elements \verb@1@ and \verb@2@: -\begin{verbatim} -Stream.cons(1, Stream.cons(2, Stream.empty)) -\end{verbatim} -As another example, here is the analogue of \verb@List.range@, -but returning a stream instead of a list: -\begin{verbatim} -def range(start: Int, end: Int): Stream[Int] = - if (start >= end) Stream.empty - else Stream.cons(start, range(start + 1, end)); -\end{verbatim} -(This function is also defined as given above in module -\verb@Stream@). Even though \verb@Stream.range@ and \verb@List.range@ -look similar, their execution behavior is completely different: - -\verb@Stream.range@ immediately returns with a \verb@Stream@ object -whose first element is \verb@start@. All other elements are computed -only when they are \emph{demanded} by calling the \verb@tail@ method -(which might be never at all). - -Streams are accessed just as lists. as for lists, the basic access -methods are \verb@isEmpty@, \verb@head@ and \verb@tail@. For instance, -we can print all elements of a stream as follows. -\begin{verbatim} -def print(xs: Stream[a]): unit = - if (!xs.isEmpty) { System.out.println(xs.head); print(xs.tail) } -\end{verbatim} -Streams also support almost all other methods defined on lists (see -below for where their methods sets differ). For instance, we can find -the second prime number between \verb@1000@ and \verb@10000@ by applying methods -\verb@filter@ and \verb@at@ on an interval stream: -\begin{verbatim} - Stream.range(1000, 10000) filter isPrime at 1 -\end{verbatim} -The difference to the previous list-based implementation is that now -we do not needlessly construct and test for primality any numbers -beyond 3. - -\paragraph{Consing and appending streams.} Two methods in class \verb@List@ -which are not supported by class \verb@Stream@ are \verb@::@ and -\verb@:::@. The reason is that these methods are dispatched on their -right-hand side argument, which means that this argument needs to be -evaluated before the method is called. For instance, in the case of -\verb@x :: xs@ on lists, the tail \verb@xs@ needs to be evaluated -before \verb@::@ can be called and the new list can be constructed. -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 \verb@tail@ operation. -The argument why list-append \verb@:::@ cannot be adapted to streams is analogous. - -Intstead of \verb@x :: xs@, one uses \verb@Stream.cons(x, xs)@ for -constructing a stream with first element \verb@x@ and (unevaluated) -rest \verb@xs@. Instead of \verb@xs ::: ys@, one uses the operation -\verb@xs append ys@. - -%\redtext -{Is there another way?} - - - -\bibliography{examples} -\end{document} - - - -\paragrph{Higher Order Functions -\bsh{Patterns of Computation over Lists} - -\bi -\item The examples show that functions over lists often have similar - structures -\item We can identify several patterns of computation like - \bi - \item Transform every element of a list in some way. - \item Extract from a list all elements satisfying a criterion. - \item Combine the elements of a list using some operator. - \ei -\item Functional programming languages enable programmers to write - general functions which implement patterns like this -\item These functions are \redtext{\em higher-order functions} which get - a transformation or an operator as one argument -\ei -\es - -Pairs, and tuples or greater arity are useful enough to - - - - - -\chapter{Generic Types and Methods} - -Classes in Scala can have type parameters. We demonstrate the use of -type parameters with iterators as an example. An iterator is an object -which traverses a sequence of values, using two abstract methods. -\begin{verbatim} -abstract class Iterator[a] { - def hasNext: boolean; - def next: a; -\end{verbatim} -Method \verb@next@ returns successive elements. Method \verb@hasNext@ -indicates whether there are still more elements to be returned by -\verb@next@. The type of the elements returned by an iterator is -arbitrary. We express this by giving the class \verb@Iterator@ the -type parameter \verb@a@. Type parameters are written in square -brackets, in contrast to normal value parameters, which are written in -parentheses. Iterators also support other methods, which are -explained later. - -Here's an iterator which traverses an interval of integer values. -\begin{verbatim} -class RangeIterator(start: int, end: int) extends Iterator[int] { - private var current = 0; - def hasNext = current < end; - def next = { - val r = current; - if (current < end) current = current + 1 - else error("end of iterator"); - r - } -} -\end{verbatim} -The superclass of \verb@RangeIterator@ is \verb@Iterator[int]@, -i.e. an iterator returning integer numbers. - -Note that, unlike the classes we have seen so far, -\verb@RangeIterator@ has internal state - - -Here is a function that takes an iterator of arbitrary element type -\verb@a@ and a procedure that maps \verb@a@-values to the trivial type \verb@unit@. -It applies the given function to every value returned by the iterator. -\begin{verbatim} - def forall[a](i: Iterator[a])(f: a => boolean): boolean = - !hasNext || { val x = next; f(x) && forall(i, f) } -\end{verbatim} -\verb@forEach@ can work with any type of iterator, -since the iterator's element type is passed as a type parameter \verb@a@. -Functions that take type parameters are called {\em polymorphic}. The term -comes from Greek, where it means ``having many forms''. - -Finally, here is an application which uses \verb@RangeIterator@ and -\verb@foreach@ to test whether a given number is prime, i.e. whether it can be -divided only by 1 and itself. -\begin{verbatim} -def isPrime(x: int) = - forall[int](new RangeIterator(2, n)) { x => x % n != 0 } -\end{verbatim} -As always, the actual parameters of \verb@forEach@ correspond to its -formal parameters. First comes the type parameter \verb@int@, which -determines the element type of the iterator which is passed next. - -\paragraph{Local Type Inference.} -Passing type parameters such as \verb@[int]@ all the time can become -tedious in applications where polymorphic functions are used a -lot. Quite often, the information in a type parameter is redundant, -because the correct parameter type can also be determined by -inspecting the function's value parameters or expected result type. -Taking the \verb@isPrime@ function as an example, we know that its -first value parameter is of type \verb@Iterator[int]@, so we can -determine the type parameter \verb@int@ from it. Scala contains a -fairly powerful local type inferencer which allows one to omit type -parameters to polymorphic functions and constructors in situations -like these. In the example above, the \verb@int@ type parameter would -have been inferred if it was not given explicitly. - -Here is another -application which prints all prime numbers between 1 and 10000. -\begin{verbatim} -forall(new RangeIterator(1, 10001)){ x => if (isPrime(x)) System.out.println(x) } -\end{verbatim} -This time, the type parameter for \verb@forEach@ was omitted (and was -inferred to be \verb@int@). - -Method \verb@append@ constructs an iterator which resumes with the -given iterator \verb@it@ after the current iterator has finished. -\begin{verbatim} - def append(that: Iterator[a]): Iterator[a] = new Iterator[a] { - def hasNext = outer.hasNext || that.hasNext; - def next = if (outer.hasNext) outer.next else that.next; - } -\end{verbatim} -The terms \verb@outer.next@ and \verb@outer.hasNext@ in the definition -of \verb@append@ call the corresponding methods as they are defined in -the enclosing \verb@Iterator@ class. Generally, an -\verb@outer@ prefix in a selection indicates an identifier that is -visible immediately outside the current class or template. If the -\verb@outer@ prefix would have been missing, -\verb@hasNext@ and \verb@next@ would have -called recursively the methods being defined in the iterator -constructed by \verb@append@, which is not what we want. - -Method \verb@filter@ constructs an iterator which returns all elements -of the original iterator that satisfy a criterion \verb@p@. -\begin{verbatim} - def filter(p: a => boolean) = new Iterator[a] { - private class Cell[T](elem_: T) { def elem = elem_; } - private var head: Cell[a] = null; - private var isAhead = false; - def hasNext: boolean = - if (isAhead) true - else if (outer.hasNext) { - head = Cell(outer.next); isAhead = p(head.elem); hasNext } - else false; - def next: a = - if (hasNext) { isAhead = false; head.elem } - else error("next on empty iterator"); - } -\end{verbatim} -Method \verb@map@ constructs an iterator which returns all elements of -the original iterator transformed by a given function \verb@f@. -\begin{verbatim} - def map[b](f: a => b) = new Iterator[b] { - def hasNext: boolean = outer.hasNext; - def next: b = f(outer.next); - } -\end{verbatim} -The return type of the transformation function \verb@f@ is -arbitrary. This is expressed by a type parameter \verb@b@ in the -signature of method \verb@map@, which represents the return type. -We also say, \verb@map@ is a {\em polymorphic} function. - -Method \verb@flatMap@ is like method \verb@map@, except that the -transformation function \verb@f@ now returns an iterator. -The result of \verb@flatMap@ is the iterator resulting from appending -together all iterators returned from successive calls of \verb@f@. -\begin{verbatim} - private var cur: Iterator[b] = new EmptyIterator[b]; - def hasNext: boolean = - if (cur.hasNext) true - else if (outer.hasNext) { cur = f(outer.next); hasNext } - else false; - def next: b = - if (cur.hasNext) cur.next - else if (outer.hasNext) { cur = f(outer.next); next } - else error("next on empty iterator"); - } -\end{verbatim} -Finally, method \verb@zip@ takes another iterator and -returns an iterator consisting of pairs of corresponding elements -returned by the two iterators. -\begin{verbatim} - def zip[b](that: Iterator[b]) = new Iterator[(a, b)] { - def hasNext = outer.hasNext && that.hasNext; - def next = (outer.next, that.next); - } -} //end iterator; -\end{verbatim} -Concrete iterators need to provide implementations for the two -abstract methods \verb@next@ and \verb@hasNext@ in class -\verb@Iterator@. The simplest iterator is \verb@EmptyIterator@ -which always returns an empty sequence: -\begin{verbatim} -class EmptyIterator[a] extends Iterator[a] { - def hasNext = false; - def next: a = error("next on empty iterator"); -} -\end{verbatim} -A more interesting iterator enumerates all elements of an array. -This iterator is formulated here as a polymorphic function. It could -have also been written as a class, like \verb@EmptyIterator@. The -difference between the two formulation is that classes also define new -types, whereas functions do not. -\begin{verbatim} -def arrayIterator[a](xs: Array[a]) = new Iterator[a] { - private var i = 0; - def hasNext: boolean = - i < xs.length; - def next: a = - if (i < xs.length) { val x = xs(i) ; i = i + 1 ; x } - else error("next on empty iterator"); -} -\end{verbatim} -Another iterator enumerates an integer interval: -\begin{verbatim} -def range(lo: int, hi: int) = new Iterator[int] { - private var i = lo; - def hasNext: boolean = - i <= hi; - def next: int = - if (i <= hi) { i = i + 1 ; i - 1 } - else error("next on empty iterator"); -} -\end{verbatim} -%In fact, enumerating integer intervals is so common that it is -%supported by a method -%\begin{verbatim} -%def to(hi: int): Iterator[int] -%\end{verbatim} -%in class \verb@int@. Hence, one could also write \verb@l to h@ instead of -%\verb@range(l, h)@. -All iterators seen so far terminate eventually. It is also possible to -define iterators that go on forever. For instance, the following -iterator returns successive integers from some start -value\footnote{Due to the finite representation of type \prog{int}, -numbers will wrap around at $2^31$.}. -\begin{verbatim} -def from(start: int) = new Iterator[int] { - private var last = start - 1; - def hasNext = true; - def next = { last = last + 1; last } -} -\end{verbatim} -Here are two examples how iterators are used. First, to print all -elements of an array \verb@xs: Array[int]@, one can write: -\begin{verbatim} - arrayIterator[int](xs) foreach (x => System.out.println(x)) -\end{verbatim} -Here, \verb@[int]@ is a type argument clause, which matches the type -parameter clause \verb@[a]@ of function \verb@arrayIterator@. It -substitutes the formal argument \verb@int@ for the formal argument -\verb@a@ in the type of the method that follows. Hence, -\verb@arrayIterator[a]@ is a function that takes an \verb@Array[int]@ -and that returns an \verb@Iterator[int]@. - -In this example, the formal type argument \verb@int@ is redundant -since it could also have been inferred from the value \verb@xs@, which -is, after all, an array of \verb@int@. The Scala compiler contains a -fairly powerful type inferencer which infers type arguments for -methods and constructors from the types of value arguments and the -expected return type. In our example, the \verb@[int]@ clause can be -inferred, so that one can abbreviate to: -\begin{verbatim} - arrayIterator(xs) foreach (x => System.out.println(x)) -\end{verbatim} -%As a second example, consider the problem of finding the indices of -%all the elements in an array of \verb@double@s greater than some -%\verb@limit@. The indices should be returned as an iterator. -%This is achieved by the following expression. -%\begin{verbatim} -%arrayIterator(xs) -% .zip(from(0)) -% .filter(x, i => x > limit) -% .map(x, i => i) -%\end{verbatim} -%The first line in this expression iterates through all array elements, -%the second lines pairs elements with their indices, the third line -%selects all value/index pairs where the value is greater than -%\verb@limit@, and the fourth line returns the index part of all -%selected pairs. - -%Note that we have omitted the type arguments for the calls of -%\verb@arrayIterator@, \verb@zip@ and \verb@map@. These are all -%implicitly inserted by the type inferencer. - - - -\es -\paragraph{Abstract Methods.} -Classes can also omit some of the definitions of their members. As an -example, consider the following class \verb@Ord@ which provides the -comparison operators \verb@<, >, <=, >=@. -%\begin{verbatim} -%abstract class Ord { -% abstract def <(that: this); -% def <=(that: this) = this < that || this == that; -% def >(that: this) = that < this; -% def >=(that: this) = that <= this; -%} -%\end{verbatim} -\begin{verbatim} -abstract class Ord { - def <(that: this): boolean; - def <=(that: this) = this < that || this == that; - def >(that: this) = that < this; - def >=(that: this) = that <= this; -} -\end{verbatim} -Since we want to leave open which objects are compared, we are unable -to give an implementation for the \verb@<@ method. However, once -\verb@<@ is given, we can define the other three comparison operators -in terms of \verb@<@ and the equality test \verb@==@ (which is defined -in class \verb@Object@). This is expressed by having in \verb@Ord@ an -{\em abstract} method \verb@<@ to which the implementations of the -other methods refer. - -\paragraph{Self References.} The name \verb@this@ refers in this class -to the current object. The type of \verb@this@ is also called -\verb@this@ (generally, every name in Scala can have a definition as a -term and another one as a type). When used as a type, \verb@this@ -refers to the type of the current object. This type is always -compatible with the class being defined (\verb@Ord@ in this case). - -\paragraph{Mixin Composition.} -We can now define a class of \verb@Rational@ numbers that -support comparison operators. -\begin{verbatim} -final class OrderedRational(n: int, d: int) - extends Rational(n, d) with Ord { - override def ==(that: OrderedRational) = - numer == that.numer && denom == that.denom; - def <(that: OrderedRational): boolean = - numer * that.denom < that.numer * denom; -} -\end{verbatim} -Class \verb@OrderedRational@ redefines method \verb@==@, which is -defined as reference equality in class \verb@Object@. It also -implements the abstract method \verb@<@ from class \verb@Ord@. In -addition, it inherits all members of class \verb@Rational@ and all -non-abstract members of class \verb@Ord@. The implementations of -\verb@==@ and \verb@<@ replace the definition of \verb@==@ in class -\verb@Object@ and the abstract declaration of \verb@<@ in class -\verb@Ord@. The other inherited comparison methods then refer to this -implementation in their body. - -The clause ``\verb@Rational(d, d) with Ord@'' is an instance of {\em -mixin composition}. It describes a template for an object that is -compatible with both \verb@Rational@ and \verb@Ord@ and that contains -all members of either class. \verb@Rational@ is called the {\em -superclass} of \verb@OrderedRational@ while \verb@Ord@ is called a -{\em mixin class}. The type of this template is the {\em compound -type} ``\verb@Rational with Ord@''. - -On the surface, mixin composition looks much like multiple -inheritance. The difference between the two becomes apparent if we -look at superclasses of inherited classes. With multiple inheritance, -both \verb@Rational@ and \verb@Ord@ would contribute a superclass -\verb@Object@ to the template. We therefore have to answer some -tricky questions, such as whether members of \verb@Object@ are present -once or twice and whether the initializer of \verb@Object@ is called -once or twice. Mixin composition avoids these complications. In the -mixin composition \verb@Rational with Ord@, class -\verb@Rational@ is treated as actual superclass of class \verb@Ord@. -A mixin composition \verb@C with M@ is well-formed as long as the -first operand \verb@C@ conforms to the declared superclass of the -second operand \verb@M@. This holds in our example, because -\verb@Rational@ conforms to \verb@Object@. In a sense, mixin composition -amounts to overriding the superclass of a class. - -\paragraph{Final Classes.} -Note that class \verb@OrderedRational@ was defined -\verb@final@. This means that no classes extending \verb@OrderedRational@ -may be defined in other parts of the program. -%Within final classes the -%type \verb@this@ is an alias of the defined class itself. Therefore, -%we could define our \verb@<@ method with an argument of type -%\verb@OrderedRational@ as a well-formed implementation of the abstract class -%\verb@less(that: this)@ in class \verb@Ord@. - - -\chapter{Generic Types and Methods} - -Classes in Scala can have type parameters. We demonstrate the use of -type parameters with iterators as an example. An iterator is an object -which traverses a sequence of values, using two abstract methods. -\begin{verbatim} -abstract class Iterator[a] { - def hasNext: boolean; - def next: a; -\end{verbatim} -Method \verb@next@ returns successive elements. Method \verb@hasNext@ -indicates whether there are still more elements to be returned by -\verb@next@. The type of elements returned by an iterator is -arbitrary. We express that by giving the class \verb@Iterator@ the -type parameter \verb@a@. Type parameters are written in square -brackets, in contrast to normal value parameters, which are written in -parentheses. Iterators also support other methods, which are -explained in the following. - -Method \verb@foreach@ applies a procedure (i.e. a function -returning \verb@unit@ to each element returned by the iterator: -\begin{verbatim} - def foreach(f: a => unit): unit = - while (hasNext) { f(next) } -\end{verbatim} - -Method \verb@append@ constructs an iterator which resumes with the -given iterator \verb@it@ after the current iterator has finished. -\begin{verbatim} - def append(that: Iterator[a]): Iterator[a] = new Iterator[a] { - def hasNext = outer.hasNext || that.hasNext; - def next = if (outer.hasNext) outer.next else that.next; - } -\end{verbatim} -The terms \verb@outer.next@ and \verb@outer.hasNext@ in the definition -of \verb@append@ call the corresponding methods as they are defined in -the enclosing \verb@Iterator@ class. Generally, an -\verb@outer@ prefix in a selection indicates an identifier that is -visible immediately outside the current class or template. If the -\verb@outer@ prefix would have been missing, -\verb@hasNext@ and \verb@next@ would have -called recursively the methods being defined in the iterator -constructed by \verb@append@, which is not what we want. - -Method \verb@filter@ constructs an iterator which returns all elements -of the original iterator that satisfy a criterion \verb@p@. -\begin{verbatim} - def filter(p: a => boolean) = new Iterator[a] { - private class Cell[T](elem_: T) { def elem = elem_; } - private var head: Cell[a] = null; - private var isAhead = false; - def hasNext: boolean = - if (isAhead) true - else if (outer.hasNext) { - head = Cell(outer.next); isAhead = p(head.elem); hasNext } - else false; - def next: a = - if (hasNext) { isAhead = false; head.elem } - else error("next on empty iterator"); - } -\end{verbatim} -Method \verb@map@ constructs an iterator which returns all elements of -the original iterator transformed by a given function \verb@f@. -\begin{verbatim} - def map[b](f: a => b) = new Iterator[b] { - def hasNext: boolean = outer.hasNext; - def next: b = f(outer.next); - } -\end{verbatim} -The return type of the transformation function \verb@f@ is -arbitrary. This is expressed by a type parameter \verb@b@ in the -signature of method \verb@map@, which represents the return type. -We also say, \verb@map@ is a {\em polymorphic} function. - -Method \verb@flatMap@ is like method \verb@map@, except that the -transformation function \verb@f@ now returns an iterator. -The result of \verb@flatMap@ is the iterator resulting from appending -together all iterators returned from successive calls of \verb@f@. -\begin{verbatim} - private var cur: Iterator[b] = new EmptyIterator[b]; - def hasNext: boolean = - if (cur.hasNext) true - else if (outer.hasNext) { cur = f(outer.next); hasNext } - else false; - def next: b = - if (cur.hasNext) cur.next - else if (outer.hasNext) { cur = f(outer.next); next } - else error("next on empty iterator"); - } -\end{verbatim} -Finally, method \verb@zip@ takes another iterator and -returns an iterator consisting of pairs of corresponding elements -returned by the two iterators. -\begin{verbatim} - def zip[b](that: Iterator[b]) = new Iterator[(a, b)] { - def hasNext = outer.hasNext && that.hasNext; - def next = (outer.next, that.next); - } -} //end iterator; -\end{verbatim} -Concrete iterators need to provide implementations for the two -abstract methods \verb@next@ and \verb@hasNext@ in class -\verb@Iterator@. The simplest iterator is \verb@EmptyIterator@ -which always returns an empty sequence: -\begin{verbatim} -class EmptyIterator[a] extends Iterator[a] { - def hasNext = false; - def next: a = error("next on empty iterator"); -} -\end{verbatim} -A more interesting iterator enumerates all elements of an array. -This iterator is formulated here as a polymorphic function. It could -have also been written as a class, like \verb@EmptyIterator@. The -difference between the two formulation is that classes also define new -types, whereas functions do not. -\begin{verbatim} -def arrayIterator[a](xs: Array[a]) = new Iterator[a] { - private var i = 0; - def hasNext: boolean = - i < xs.length; - def next: a = - if (i < xs.length) { val x = xs(i) ; i = i + 1 ; x } - else error("next on empty iterator"); -} -\end{verbatim} -Another iterator enumerates an integer interval: -\begin{verbatim} -def range(lo: int, hi: int) = new Iterator[int] { - private var i = lo; - def hasNext: boolean = - i <= hi; - def next: int = - if (i <= hi) { i = i + 1 ; i - 1 } - else error("next on empty iterator"); -} -\end{verbatim} -%In fact, enumerating integer intervals is so common that it is -%supported by a method -%\begin{verbatim} -%def to(hi: int): Iterator[int] -%\end{verbatim} -%in class \verb@int@. Hence, one could also write \verb@l to h@ instead of -%\verb@range(l, h)@. -All iterators seen so far terminate eventually. It is also possible to -define iterators that go on forever. For instance, the following -iterator returns successive integers from some start -value\footnote{Due to the finite representation of type \prog{int}, -numbers will wrap around at $2^31$.}. -\begin{verbatim} -def from(start: int) = new Iterator[int] { - private var last = start - 1; - def hasNext = true; - def next = { last = last + 1; last } -} -\end{verbatim} -Here are two examples how iterators are used. First, to print all -elements of an array \verb@xs: Array[int]@, one can write: -\begin{verbatim} - arrayIterator[int](xs) foreach (x => System.out.println(x)) -\end{verbatim} -Here, \verb@[int]@ is a type argument clause, which matches the type -parameter clause \verb@[a]@ of function \verb@arrayIterator@. It -substitutes the formal argument \verb@int@ for the formal argument -\verb@a@ in the type of the method that follows. Hence, -\verb@arrayIterator[a]@ is a function that takes an \verb@Array[int]@ -and that returns an \verb@Iterator[int]@. - -In this example, the formal type argument \verb@int@ is redundant -since it could also have been inferred from the value \verb@xs@, which -is, after all, an array of \verb@int@. The Scala compiler contains a -fairly powerful type inferencer which infers type arguments for -methods and constructors from the types of value arguments and the -expected return type. In our example, the \verb@[int]@ clause can be -inferred, so that one can abbreviate to: -\begin{verbatim} - arrayIterator(xs) foreach (x => System.out.println(x)) -\end{verbatim} -%As a second example, consider the problem of finding the indices of -%all the elements in an array of \verb@double@s greater than some -%\verb@limit@. The indices should be returned as an iterator. -%This is achieved by the following expression. -%\begin{verbatim} -%arrayIterator(xs) -% .zip(from(0)) -% .filter(x, i => x > limit) -% .map(x, i => i) -%\end{verbatim} -%The first line in this expression iterates through all array elements, -%the second lines pairs elements with their indices, the third line -%selects all value/index pairs where the value is greater than -%\verb@limit@, and the fourth line returns the index part of all -%selected pairs. - -%Note that we have omitted the type arguments for the calls of -%\verb@arrayIterator@, \verb@zip@ and \verb@map@. These are all -%implicitly inserted by the type inferencer. - -\chapter{\label{sec:for-notation}For-Comprehensions} - -The last chapter has demonstrated that the use of higher-order -functions over sequences can lead to very concise programs. But -sometimes the level of abstraction required by these functions makes a -program hard to understand. - -Here, Scala's \verb@for@ notation can help. For instance, say we are -given a sequence \verb@persons@ of persons with \verb@name@ and -\verb@age@ fields. That sequence could be an array, or a list, or an -iterator, or some other type implementing the sequence abstraction -(this will be made more precise below). To print the names of all -persons in the sequence which are aged over 20, one writes: -\begin{verbatim} -for { val p <- persons; p.age > 20 } yield p.name -\end{verbatim} -This is equivalent to the following expression , which uses -higher-order functions \verb@filter@ and \verb@map@: -\begin{verbatim} -persons filter (p => p.age > 20) map (p => p.name) -\end{verbatim} -The for-expression looks a bit like a for-loop in imperative languages, -except that it constructs a list of the results of all iterations. - -Generally, a for-comprehension is of the form -\begin{verbatim} -for ( s ) yield e -\end{verbatim} -(Instead of parentheses, braces may also be used.) -Here, \verb@s@ is a sequence of {\em generators} and {\em filters}. -\begin{itemize} -\item A {\em generator} is of the form \verb@val x <- e@, -where \verb@e@ is a list-valued expression. It binds \verb@x@ to -successive values in the list. -\item A {\em filter} is an expression \verb@f@ of type \verb@boolean@. -It omits from consideration all bindings for which \verb@f@ is \verb@false@. -\end{itemize} -The sequence must start with a generator. -If there are several generators in a sequence, later generators vary -more rapidly than earlier ones. - -Here are two examples that show how for-comprehensions are used. - -First, given a positive integer \verb@n@, find all pairs of positive -integers -\verb@i@, \verb@j@, where \verb@1 <= j < i <= n@ such that \verb@i + j@ is prime. -\begin{verbatim} -for \={ \=val i <- range(1, n); - \> \>val j <- range(1, i-1); - \> \>isPrime(i+j) -} yield (i, j) -\end{verbatim} - -As second example, the scalar product of two vectors \verb@xs@ and -\verb@ys@ can now be written as -follows. -\begin{verbatim} - sum (for { val (x, y) <- xs zip ys } yield x * y) -\end{verbatim} -The for-notation is essentially equivalent to common operations of -database query languages. For instance, say we are given a book -database \verb@books@, represented as a list of books, where -\verb@Book@ is defined as follows. -\begin{verbatim} -abstract class Book { - val title: String; - val authors: List[String] -} -\end{verbatim} -\begin{verbatim} -val books: List[Book] = [ - new Book { - val title = "Structure and Interpretation of Computer Programs"; - val authors = ["Abelson, Harald", "Sussman, Gerald J."]; - }, - new Book { - val title = "Principles of Compiler Design"; - val authors = ["Aho, Alfred", "Ullman, Jeffrey"]; - }, - new Book { - val title = "Programming in Modula-2"; - val authors = ["Wirth, Niklaus"]; - } -]; -\end{verbatim} -Then, to find the titles of all books whose author's last name is ``Ullman'': -\begin{verbatim} -for { val b <- books; val a <- b.authors; a startsWith "Ullman" -} yield b.title -\end{verbatim} -(Here, \verb@startsWith@ is a method in \verb@java.lang.String@). Or, -to find the titles of all books that have the string ``Program'' in -their title: -\begin{verbatim} -for { val b <- books; (b.title indexOf "Program") >= 0 -} yield b.title -\end{verbatim} -Or, to find the names of all authors that have written at least two -books in the database. -\begin{verbatim} -for { \=val b1 <- books; - \>val b2 <- books; - \>b1 != b2; - \>val a1 <- b1.authors; - \>val a2 <- b2.authors; - \>a1 == a2 } yield a1 -\end{verbatim} -The last solution is not yet perfect, because authors will appear -several times in the list of results. We still need to remove -duplicate authors from result lists. This can be achieved with the -following function. -\begin{verbatim} -def removeDuplicates[a](xs: List[a]): List[a] = - if (xs.isEmpty) xs - else xs.head :: removeDuplicates(xs.tail filter (x => x != xs.head)); -\end{verbatim} -The last expression can be equivalently expressed as follows. -\begin{verbatim} -xs.head :: removeDuplicates(for (val x <- xs.tail; x != xs.head) yield x) -\end{verbatim} - -\subsection*{Translation of \prog{for}} - -Every for-comprehensions can be expressed in terms of the three -higher-order functions \verb@map@, \verb@flatMap@ and \verb@filter@. -Here is the translation scheme, which is also used by the Scala compiler. -\begin{itemize} -\item -A simple for-comprehension -\begin{verbatim} -for (val x <- e) yield e' -\end{verbatim} -is translated to -\begin{verbatim} -e.map(x => e') -\end{verbatim} -\item -A for-comprehension -\begin{verbatim} -for (val x <- e; f; s) yield e' -\end{verbatim} -where \verb@f@ is a filter and \verb@s@ is a (possibly empty) -sequence of generators or filters -is translated to -\begin{verbatim} -for (val x <- e.filter(x => f); s) yield e' -\end{verbatim} -and then translation continues with the latter expression. -\item -A for-comprehension -\begin{verbatim} -for (val x <- e; y <- e'; s) yield e'' -\end{verbatim} -where \verb@s@ is a (possibly empty) -sequence of generators or filters -is translated to -\begin{verbatim} -e.flatMap(x => for (y <- e'; s) yield e'') -\end{verbatim} -and then translation continues with the latter expression. -\end{itemize} -For instance, taking our "pairs of integers whose sum is prime" example: -\begin{verbatim} -for \= { \= val i <- range(1, n); - \> \> val j <- range(1, i-1); - \> \> isPrime(i+j) -} yield (i, j) -\end{verbatim} -Here is what we get when we translate this expression: -\begin{verbatim} -range(1, n) - .flatMap(i => - range(1, i-1) - .filter(j => isPrime(i+j)) - .map(j => (i, j))) -\end{verbatim} - -\exercise -Define the following function in terms of \verb@for@. -\begin{verbatim} -def concat(xss: List[List[a]]): List[a] = - (xss foldr []) { xs, ys => xs ::: ys } -\end{verbatim} -\exercise -Translate -\begin{verbatim} -for { val b <- books; val a <- b.authors; a startsWith "Bird" } yield b.title -for { val b <- books; (b.title indexOf "Program") >= 0 } yield b.title -\end{verbatim} -to higher-order functions. - -We have seen that the for-translation only relies on the presence of -methods \verb@map@, -\verb@flatMap@, and \verb@filter@. -This gives programmers the possibility to have for-syntax for -other types as well -- one only needs to define \verb@map@, -\verb@flatMap@, and \verb@filter@ for these types. -That's also why we were able to define \verb@for@ at the same time for -arrays, iterators, and lists -- all these types have the required -three methods \verb@map@,\verb@flatMap@, and \verb@filter@ as members. -Of course, it is also possible for users and library designers to -define other types with these methods. There are many examples where -this is useful: Databases, XML trees, optional values. We will see in -Chapter~\ref{sec:parsers-results} how for-comprehensions can be used in the -definition of parsers for context-free grammars that construct -abstract syntax trees. - -\chapter{\label{sec:simple-examples}Pattern Matching} - -\todo{Complete} - -Consider binary trees whose leafs contain integer arguments. This can -be described by a class for trees, with subclasses for leafs and -branch nodes: -\begin{verbatim} -abstract class Tree; -case class Branch(left: Tree, right: Tree) extends Tree; -case class Leaf(x: int) extends Tree; -\end{verbatim} -Note that the class \verb@Tree@ is not followed by an extends -clause or a body. This defines \verb@Tree@ to be an empty -subclass of \verb@Object@, as if we had written -\begin{verbatim} -class Tree extends Object {} -\end{verbatim} -Note also that the two subclasses of \verb@Tree@ have a \verb@case@ -modifier. That modifier has two effects. First, it lets us construct -values of a case class by simply calling the constructor, without -needing a preceding \verb@new@. Example: -\begin{verbatim} -val tree1 = Branch(Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4))) -\end{verbatim} -Second, it lets us use constructors for these classes in patterns, as -is illustrated in the following example. -\begin{verbatim} -def sumLeaves(t: Tree): int = t match { - case Branch(l, r) => sumLeaves(l) + sumLeaves(r) - case Leaf(x) => x -} -\end{verbatim} -The function \verb@sumLeaves@ sums up all the integer values in the -leaves of a given tree \verb@t@. It is is implemented by calling the -\verb@match@ method of \verb@t@ with a {\em choice expression} as -argument (\verb@match@ is a predefined method in class \verb@Object@). -The choice expression consists of two cases which both -relate a pattern with an expression. The pattern of the first case, -\verb@Branch(l, r)@ matches all instances of class \verb@Branch@ -and binds the {\em pattern variables} \verb@l@ and \verb@r@ to the -constructor arguments, i.e.\ the left and right subtrees of the -branch. Pattern variables always start with a lower case letter; to -avoid ambiguities, constructors in patterns should start with an upper -case letter. - -The effect of the choice expression is to select the first alternative -whose pattern matches the given select value, and to evaluate the body -of this alternative in a context where pattern variables are bound to -corresponding parts of the selector. For instance, the application -\verb@sumLeaves(tree1)@ would select the first alternative with the -\verb@Branch(l,r)@ pattern, and would evaluate the expression -\verb@sumLeaves(l) + sumLeaves(r)@ with bindings -\begin{verbatim} -l = Branch(Leaf(1), Leaf(2)), r = Branch(Leaf(3), Leaf(4)). -\end{verbatim} -As another example, consider the following class -\begin{verbatim} -abstract final class Option[+a]; -case object None extends Option[All]; -case class Some[a](item: a) extends Option[a]; -\end{verbatim} -... - -%\todo{Several simple and intermediate examples needed}. - -\begin{verbatim} -def find[a,b](it: Iterator[(a, b)], x: a): Option[b] = { - var result: Option[b] = None; - while (it.hasNext && result == None) { - val (x1, y) = it.next; - if (x == x1) result = Some(y) - } - result -} -find(xs, x) match { - case Some(y) => System.out.println(y) - case None => System.out.println("no match") -} -\end{verbatim} - -\comment{ - - -class MaxCounter { - var maxVal: Option[int] = None; - def set(x: int) = maxVal match { - case None => maxVal = Some(x) - case Some(y) => maxVal = Some(Math.max(x, y)) - } -} -\end{verbatim} -} -\comment{ -\begin{verbatim} -class Stream[a] = List[a] - -module Stream { - def concat(xss: Stream[Stream[a]]): Stream[a] = { - let result: Stream[a] = xss match { - case [] => [] - case [] :: xss1 => concat(xss1) - case (x :: xs) :: xss1 => x :: concat(xs :: xss1) - } - result - } -} -\end{verbatim} -} -\comment{ -\chapter{Implementing Abstract Types: Search Trees} - -This chapter presents unbalanced binary search trees, implemented in -three different styles: algebraic, object-oriented, and imperative. -In each case, a search tree package is seen as an implementation -of a class {\em MapStruct}. -\begin{verbatim} -abstract class MapStruct[kt, vt] { - abstract type Map extends kt => vt { - def apply(key: kt): vt; - def extend(key: kt, value: vt): Map; - def remove(key: kt): Map; - def domain: Stream[kt]; - def range: Stream[vt]; - } - def empty: Map; -} -\end{verbatim} -The \verb@MapStruct@ class is parameterized with a type of keys -\verb@kt@ and a type of values \verb@vt@. It -specifies an abstract type \verb@Map@ and an abstract value -\verb@empty@, which represents empty maps. Every implementation -\verb@Map@ needs to conform to that abstract type, which -extends the function type \verb@kt => vt@ -with four new -methods. The method \verb@domain@ yields a stream that enumerates the -map's domain, i.e. the set of keys that are mapped to non-null values. -The method \verb@range@ yields a stream that enumerates the function's -range, i.e.\ the values obtained by applying the function to arguments -in its domain. The method -\verb@extend@ extends the map with a given key/value binding, whereas -\verb@remove@ removes a given key from the map's domain. Both -methods yield a new map value as result, which has the same -representation as the receiver object. - -\begin{figure}[t] -\begin{verbatim} -class AlgBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] { - private case - Empty extends Map, - Node(key: kt, value: vt, l: Map, r: Map) extends Map - - final class Map extends kt => vt { - def apply(key: kt): vt = this match { - case Empty => null - case Node(k, v, l, r) => - if (key < k) l.apply(key) - else if (key > k) r.apply(key) - else v - } - - def extend(key: kt, value: vt): Map = this match { - case Empty => Node(k, v, Empty, Empty) - case Node(k, v, l, r) => - if (key < k) Node(k, v, l.extend(key, value), r) - else if (key > k) Node(k, v, l, r.extend(key, value)) - else Node(k, value, l, r) - } - - def remove(key: kt): Map = this match { - case Empty => Empty - case Node(k, v, l, r) => - if (key < k) Node(k, v, l.remove(key), r) - else if (key > k) Node(k, v, l, r.remove(key)) - else if (l == Empty) r - else if (r == Empty) l - else { - val midKey = r.domain.head - Node(midKey, r.apply(midKey), l, r.remove(midKey)) - } - } - - def domain: Stream[kt] = this match { - case Empty => [] - case Node(k, v, l, r) => Stream.concat([l.domain, [k], r.domain]) - } - def range: Stream[vt] = this match { - case Empty => [] - case Node(k, v, l, r) => Stream.concat([l.range, [v], r.range]) - } - } - def empty: Map = Empty -} -\end{verbatim} -\caption{\label{fig:algbintree}Algebraic implementation of binary -search trees} -\end{figure} -We now present three implementations of \verb@Map@, which are all -based on binary search trees. The \verb@apply@ method of a map is -implemented in each case by the usual search function over binary -trees, which compares a given key with the key stored in the topmost -tree node, and depending on the result of the comparison, searches the -left or the right hand sub-tree. The type of keys must implement the -\verb@Ord@ class, which contains comparison methods -(see Chapter~\ref{chap:classes} for a definition of class \verb@Ord@). - -The first implementation, \verb@AlgBinTree@, is given in -Figure~\ref{fig:algbintree}. It represents a map with a -data type \verb@Map@ with two cases, \verb@Empty@ and \verb@Node@. - -Every method of \verb@AlgBinTree[kt, vt].Map@ performs a pattern -match on the value of -\verb@this@ using the \verb@match@ method which is defined as postfix -function application in class \verb@Object@ (\sref{sec:class-object}). - -The functions \verb@domain@ and \verb@range@ return their results as -lazily constructed lists. The \verb@Stream@ class is an alias of -\verb@List@ which should be used to indicate the fact that its values -are constructed lazily. - -\begin{figure}[thb] -\begin{verbatim} -class OOBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] { - abstract class Map extends kt => vt { - def apply(key: kt): v - def extend(key: kt, value: vt): Map - def remove(key: kt): Map - def domain: Stream[kt] - def range: Stream[vt] - } - module empty extends Map { - def apply(key: kt) = null - def extend(key: kt, value: vt) = Node(key, value, empty, empty) - def remove(key: kt) = empty - def domain = [] - def range = [] - } - private class Node(k: kt, v: vt, l: Map, r: Map) extends Map { - def apply(key: kt): vt = - if (key < k) l.apply(key) - else if (key > k) r.apply(key) - else v - def extend(key: kt, value: vt): Map = - if (key < k) Node(k, v, l.extend(key, value), r) - else if (key > k) Node(k, v, l, r.extend(key, value)) - else Node(k, value, l, r) - def remove(key: kt): Map = - if (key < k) Node(k, v, l.remove(key), r) - else if (key > k) Node(k, v, l, r.remove(key)) - else if (l == empty) r - else if (r == empty) l - else { - val midKey = r.domain.head - Node(midKey, r(midKey), l, r.remove(midKey)) - } - def domain: Stream[kt] = Stream.concat([l.domain, [k], r.domain] ) - def range: Stream[vt] = Stream.concat([l.range, [v], r.range]) - } -} -\end{verbatim} -\caption{\label{fig:oobintree}Object-oriented implementation of binary -search trees} -\end{figure} - -The second implementation of maps is given in -Figure~\ref{fig:oobintree}. Class \verb@OOBinTree@ implements the -type \verb@Map@ with a module \verb@empty@ and a class -\verb@Node@, which define the behavior of empty and non-empty trees, -respectively. - -Note the different nesting structure of \verb@AlgBinTree@ and -\verb@OOBinTree@. In the former, all methods form part of the base -class \verb@Map@. The different behavior of empty and non-empty trees -is expressed using a pattern match on the tree itself. In the -latter, each subclass of \verb@Map@ defines its own set of -methods, which override the methods in the base class. The pattern -matches of the algebraic implementation have been replaced by the -dynamic binding that comes with method overriding. - -Which of the two schemes is preferable depends to a large degree on -which extensions of the type are anticipated. If the type is later -extended with a new alternative, it is best to keep methods in each -alternative, the way it was done in \verb@OOBinTree@. On the other -hand, if the type is extended with additional methods, then it is -preferable to keep only one implementation of methods and to rely on -pattern matching, since this way existing subclasses need not be -modified. - -\begin{figure} -\begin{verbatim} -class MutBinTree[kt extends Ord, vt] extends MapStruct[kt, vt] { - class Map(key: kt, value: vt) extends kt => vt { - val k = key - var v = value - var l = empty, r = empty - - def apply(key: kt): vt = - if (this eq empty) null - else if (key < k) l.apply(key) - else if (key > k) r.apply(key) - else v - - def extend(key: kt, value: vt): Map = - if (this eq empty) Map(key, value) - else { - if (key < k) l = l.extend(key, value) - else if (key > k) r = r.extend(key, value) - else v = value - this - } - - def remove(key: kt): Map = - if (this eq empty) this - else if (key < k) { l = l.remove(key) ; this } - else if (key > k) { r = r.remove(key) ; this } - else if (l eq empty) r - else if (r eq empty) l - else { - var mid = r - while (!(mid.l eq empty)) { mid = mid.l } - mid.r = r.remove(mid.k) - mid.l = l - mid - } - - def domain: Stream[kt] = Stream.concat([l.domain, [k], r.domain]) - def range: Stream[vt] = Stream.concat([l.range, [v], r.range]) - } - let empty = new Map(null, null) -} -\end{verbatim} -\caption{\label{fig:impbintree}Side-effecting implementation of binary -search trees} -\end{figure} - -The two versions of binary trees presented so far are {\em -persistent}, in the sense that maps are values that cannot be changed -by side effects. By contrast, in the next implementation of binary -trees, the implementations of \verb@extend@ and -\verb@remove@ do have an effect on the state of their receiver -object. This corresponds to the way binary trees are usually -implemented in imperative languages. The new implementation can lead -to some savings in computing time and memory allocation, but care is -required not to use the original tree after it has been modified by a -side-effecting operation. - -In this implementation, \verb@value@, \verb@l@ and \verb@r@ are -variables that can be affected by method calls. The -class \verb@MutBinTree[kt, vt].Map@ takes two instance parameters -which define the \verb@key@ value and the initial value of the -\verb@value@ variable. Empty trees are represented by a -value \verb@empty@, which has \verb@null@ (signifying undefined) in -both its key and value fields. Note that this value needs to be -defined lazily using \verb@let@ since its definition involves the -creation of a -\verb@Map@ object, -which accesses \verb@empty@ recursively as part of its initialization. -All methods test first whether the current tree is empty using the -reference equality operator \verb@eq@ (\sref{sec:class-object}). - -As a program using the \verb@MapStruct@ abstraction, consider a function -which creates a map from strings to integers and then applies it to a -key string: -\begin{verbatim} -def mapTest(def mapImpl: MapStruct[String, int]): int = { - val map: mapImpl.Map = mapImpl.empty.extend("ab", 1).extend("bx", 3) - val x = map("ab") // returns 1 -} -\end{verbatim} -The function is parameterized with the particular implementation of -\verb@MapStruct@. It can be applied to any one of the three implementations -described above. E.g.: -\begin{verbatim} -mapTest(AlgBinTree[String, int]) -mapTest(OOBinTree[String, int]) -mapTest(MutBinTree[String, int]) -\end{verbatim} -} -\chapter{Programming with Higher-Order Functions: Combinator Parsing} - -In this chapter we describe how to write combinator parsers in -Scala. Such parsers are constructed from predefined higher-order -functions, so called parser combinators, that closely model the -constructions of an EBNF grammar \cite{ebnf}. - -As running example, we consider parsers for arithmetic expressions -described by the following context-free grammar. -\bda{p{3cm}cp{10cm}} -letter &::=& /* all letters */ \\ -digit &::=& /* all digits */ \\[0.5em] -ident &::=& letter \{letter $|$ digit \}\\ -number &::=& digit \{digit\}\\[0.5em] - -expr &::=& expr1 \{`+' expr1 $|$ `$-$' expr1\}\\ -expr1 &::=& expr2 \{`*' expr2 $|$ `/' expr2\}\\ -expr2 &::=& ident $|$ number $|$ `(' expr `)' -\eda - -\section{Simple Combinator Parsing} - -In this section we will only be concerned with the task of recognizing -input strings, not with processing them. So we can describe parsers -by the sets of input strings they accept. There are two -fundamental operators over parsers: -\verb@&&&@ expresses the sequential composition of a parser with -another, while \verb@|||@ expresses an alternative. These operations -will both be defined as methods of a \verb@Parser@ class. We will -also define constructors for the following primitive parsers: - -\begin{quote}\begin{tabular}{ll} -\verb@empty@ & The parser that accepts the empty string -\\ -\verb@fail@ & The parser that accepts no string -\\ -\verb@chr@ & The parser that accepts any character. -\\ -\verb@chr(c: char)@ - & The parser that accepts the single-character string ``$c$''. -\\ -\verb@chrWith(p: char => boolean)@ - & The parser that accepts single-character strings - ``$c$'' \\ - & for which $p(c)$ is true. -\end{tabular}\end{quote} - -There are also the two higher-order parser combinators \verb@opt@, -expressing optionality and \verb@rep@, expressing repetition. -For any parser $p$, \verb@opt($p$)@ yields a parser that -accepts the strings accepted by $p$ or else the empty string, while -\verb@rep($p$)@ accepts arbitrary sequences of the strings accepted by -$p$. In EBNF, \verb@opt($p$)@ corresponds to $[p]$ and \verb@rep($p$)@ -corresponds to $\{p\}$. - -The central idea of parser combinators is that parsers can be produced -by a straightforward rewrite of the grammar, replacing \verb@::=@ with -\verb@=@, sequencing with -\verb@&&&@, choice -\verb@|@ with \verb@|||@, repetition \verb@{...}@ with -\verb@rep(...)@ and optional occurrence with \verb@[...]@. -Applying this process to the grammar of arithmetic -expressions yields: -\begin{verbatim} -module ExprParser { - import Parse; - - def letter \= = \= chrWith(c => c.isLetter); - def digit \= = \> chrWith(c => c.isDigit); - - def ident \> = \> letter &&& rep(letter ||| digit); - def number \> = \> digit &&& rep(digit); - - def expr:Parser\> = expr1 &&& rep((chr('+') &&& expr1) ||| (chr('-') &&& expr1)); - def expr1 \> = expr2 &&& rep((chr('*') &&& expr2) ||| (chr('/') &&& expr2)); - def expr2 \> = ident ||| number ||| (chr('(') &&& expr &&& chr(')')); -} -\end{verbatim} -It remains to explain how to implement a library with the combinators -described above. We will pack combinators and their underlying -implementation in a module \verb@Parse@. The first question to decide -is which underlying representation type to use for a parser. We treat -parsers here as functions that take a list of characters as input -parameter and that yield a parse result. -\begin{verbatim} -module Parse { - - type Result = Option[List[char]]; - - abstract class Parser extends Function1[List[char],Result] { -\end{verbatim} -\comment{ -The \verb@Option@ type is predefined as follows. -\begin{verbatim} -abstract final class Option[a]; -case class None[a] extends Option[a]; -case class Some[a](x: a) extends Option[a]; -\end{verbatim} -} -A parser returns either the constant \verb@None@, which -signifies that the parser did not recognize a legal input string, or -it returns a value \verb@Some(in1)@ where \verb@in1@ represents that -part of the input list that the parser did not consume. - -Parsers are instances of functions from \verb@List[char]@ to -\verb@Parse.Result@, which also implement the combinators -for sequence and alternative. This is modeled by -defining \verb@Parser@ as a class that extends type -\verb@Function1[List[char],Result]@ and that defines an \verb@apply@ -method, as well as methods \verb@&&&@ and \verb@|||@. -\begin{verbatim} - abstract def apply(in: List[char]): Result; -\end{verbatim} -\begin{verbatim} - def &&& (def p: Parser) = new Parser { - def apply(in: List[char]) = outer.apply(in) match { - case Some(in1) => p(in1) - case n => n - } - } - - def ||| (def p: Parser) = new Parser { - def apply(in: List[char]) = outer.apply(in) match { - case None => p(in) - case s => s - } - } - } -\end{verbatim} -The implementations of the primitive parsers \verb@empty@, \verb@fail@, -\verb@chrWith@ and \verb@chr@ are as follows. -\begin{verbatim} - - def empty = new Parser { def apply(in: List[char]) = Some(in) } - - def fail = new Parser { def apply(in: List[char]) = None[List[char]] } - - def chrWith(p: char => boolean) = new Parser { - def apply(in: List[char]) = in match { - case [] => None[List[char]] - case (c :: in1) => if (p(c)) Some(in1) else None[List[char]] - } - } - - def chr(c: char): Parser = chrWith(d => d == c); -\end{verbatim} -The higher-order parser combinators \verb@opt@ and \verb@rep@ can be -defined in terms of the combinators for sequence and alternative: -\begin{verbatim} - def opt(p: Parser): Parser = p ||| empty; - def rep(p: Parser): Parser = opt(rep1(p)); - def rep1(p: Parser): Parser = p &&& rep(p); -} // end Parser -\end{verbatim} -This is all that's needed. Parsers such as the one for arithmetic -expressions given above can now be composed from these building -blocks. These parsers need not refer to the underlying implementation of -parsers as functions from input lists to parse results. - -The presented combinator parsers use backtracking to change from one -alternative to another. If one restricts the focus to LL(1) grammars, -a non-backtracking implementation of parsers is also possible. This -implementation can then be based on iterators instead of lists. - -\section{\label{sec:parsers-results}Parsers that Return Results} - -The combinator library of the previous section does not support the -generation of output from parsing. But usually one does not just want -to check whether a given string belongs to the defined language, one -also wants to convert the input string into some internal -representation such as an abstract syntax tree. - -In this section, we modify our parser library to build parsers that -produce results. We will make use of the for-comprehensions introduced -in Chapter~\ref{sec:for-notation}. The basic combinator of sequential -composition, formerly \verb@p &&& q@, now becomes -\begin{verbatim} -for (val x <- p; val y <- q) yield e -\end{verbatim}. -Here, the names \verb@x@ and \verb@y@ are bound to the results of -executing the parsers \verb@p@ and \verb@q@. \verb@e@ is an expression -that uses these results to build the tree returned by the composed -parser. - -Before describing the implementation of the new parser combinators, we -explain how the new building blocks are used. Say we want to modify -our arithmetic expression parser so that it returns an abstract syntax -tree of the parsed expression. The class of syntax trees is given by: -\begin{verbatim} -abstract class Tree; -case class Var(n: String) extends Tree; -case class Num(n: int) extends Tree; -case class Binop(op: char, l: Tree, r: Tree) extends Tree; -\end{verbatim} -That is, a syntax tree is a named variable, an integer number, or a -binary operation with two operand trees and a character indicating the -operation. - -As a first step towards parsers that produce syntax trees, we need to -modify the ``micro-syntax'' parsers \verb@letter@, \verb@digit@, -\verb@ident@ and \verb@number@ so that they return representations of -the parsed input: -\begin{verbatim} -def letter: Parser[char] = chrWith(c => c.isLetter); -def digit : Parser[char] = chrWith(c => c.isDigit); - -def ident: Parser[String] = - for (val c <- letter; val cs <- rep(letter ||| digit)) - yield ((c :: cs) foldr "") {c, s => c+ s}; - -def number: Parser[int] = - for (val d <- digit; val ds <- rep(digit)) - yield ((d - '0') :_foldl ds) {x, y => x * 10 + (y - '0')}; -\end{verbatim} -The \verb@letter@ and \verb@digit@ parsers simply return the letter -that was parsed. The \verb@ident@ and \verb@number@ parsers return the -string, respectively integer number that was parsed. In both cases, -sub-parsers are applied in a for-comprehension and their results are -embedded in the result of the calling parser. The remainder of the -parser for arithmetic expressions follows the same scheme. -\begin{verbatim} -def expr: Parser[Tree] = - for { - val e1 <- expr1; - val es <- rep ( - for { - val op <- chr('+') ||| chr('-'); - val e <- expr1 - } yield (x => Binop(op, x, e)) : Tree => Tree - ) - } yield applyAll(es, e1); -\end{verbatim} -\begin{verbatim} -def expr1: Parser[Tree] = - for { - val e1 <- expr2; - val es <- rep ( - for { - val op <- chr('*') ||| chr('/'); - val e <- expr2 - } yield (x => Binop(op, x, e)) : Tree => Tree - ) - } yield applyAll(es, e1); -\end{verbatim} -\begin{verbatim} -def expr2: Parser[Tree] = { - \= ( for { val n <- ident } yield Var(n) : Tree ) - |||\> ( for { val n <- number } yield Num(n) : Tree ) - |||\> ( for { val _ <- chr('('); val e <- expr; val _ <- chr(')') } yield e ); -} -\end{verbatim} -Note the treatment of the repetitions in \verb@expr@ and -\verb@expr1@. The parser for an expression suffix $op;e$ consisting of an -operator $op$ and an expression $e$ returns a function, which, given a -left operand expression $d$, constructs a \verb@Binop@ node that -represents $d;op;e$. The \verb@rep@ parser combinator forms a list of -all these functions. The final \verb@yield@ part applies all functions -to the first operand in the sequence, which is represented by -\verb@e1@. Here \verb@applyAll@ applies the list of functions passed as its first -argument to its second argument. It is defined as follows. -\begin{verbatim} -def applyAll[a](fs: List[a => a], e: a): a = - (e :_foldl fs) { x, f => f(x) } -\end{verbatim} -We now present the parser combinators that support the new -scheme. Parsers that succeed now return a parse result besides the -un-consumed input. -\begin{verbatim} -module Parse { - - type Result[a] = Option[(a, List[char])] -\end{verbatim} -Parsers are parameterized with the type of their result. The class -\verb@Parser[a]@ now defines new methods \verb@map@, \verb@flatMap@ -and \verb@filter@. The \verb@for@ expressions are mapped by the -compiler to calls of these functions using the scheme described in -Chapter~\ref{sec:for-notation}. - -Here is the complete definition of the new \verb@Parser@ class. -\begin{verbatim} - abstract class Parser[a] extends Function1[List[char],Result[a]] { - - def apply(in: List[char]): Result[a]; - - def filter(p: a => boolean) = new Parser[a] { - def apply(in: List[char]): Result[a] = outer.apply(in) match { - case Some((x, in1)) => if (p(x)) Some((x, in1)) else None - case None => None - } - } - - def map[b](f: a => b) = new Parser[b] { - def apply(in: List[char]): Result[b] = outer.apply(in) match { - case Some((x, in1)) => Some((f(x), in1)) - case None => None - } - } - - def flatMap[b](f: a => Parser[b]) = new Parser[b] { - def apply(in: List[char]): Result[b] = outer.apply(in) match { - case Some((x, in1)) => f(x)(in1) - case None => None - } - } - - def ||| (def p: Parser[a]) = new Parser[a] { - def apply(in: List[char]): Result[a] = outer.apply(in) match { - case None => p(in) - case s => s - } - } - - def &&& [b](def p: Parser[b]): Parser[b] = - for (val _ <- this; val result <- p) yield result; - } -\end{verbatim} - -The \verb@filter@ method takes as parameter a predicate $p$ which it -applies to the results of the current parser. If the predicate is -false, the parser fails by returning \verb@None@; otherwise it returns -the result of the current parser. The \verb@map@ method takes as -parameter a function $f$ which it applies to the results of the -current parser. The \verb@flatMap@ tales as parameter a function -\verb@f@ which returns a parser. It applies \verb@f@ to the result of -the current parser and then continues with the resulting parser. The -\verb@|||@ method is essentially defined as before. The -\verb@&&&@ method can now be defined in terms of \verb@for@. - -% Here is the code for fail, chrWith and chr -% -%\begin{verbatim} -% def fail[a] = new Parser[a] { def apply(in: List[char]) = None[(a,List[char])] } -% -% def chrWith(p: char => boolean) = new Parser[char] { -% def apply(in: List[char]) = in match { -% case [] => None[(char,List[char])] -% case (c :: in1) => if (p(c)) Some((c,in1)) else None[(char,List[char])] -% } -% } -% -% def chr(c: char): Parser[char] = chrWith(d => d == c); -%\end{verbatim} -The primitive parser \verb@succeed@ replaces \verb@empty@. It consumes -no input and returns its parameter as result. -\begin{verbatim} - def succeed[a](x: a) = new Parser[a] { - def apply(in: List[char]) = Some((x, in)) - } -\end{verbatim} -The \verb@fail@ parser is as before. The parser combinators -\verb@rep@ and \verb@opt@ now also return results. \verb@rep@ returns -a list which contains as elements the results of each iteration of its -sub-parser. \verb@opt@ returns an -\verb@Option@ type which indicates whether something was recognized by -its sub-parser. -\begin{verbatim} - def rep[a](p: Parser[a]): Parser[List[a]] = - rep1(p) ||| succeed([]); - - def rep1[a](p: Parser[a]): Parser[List[a]] = - for (val x <- p; val xs <- rep(p)) yield x :: xs; - - def opt[a](p: Parser[a]): Parser[Option [a]] = - { for (val x <- p) yield (Some(x): Option[a]) } ||| succeed((None: Option[a])); -} // end Parse -\end{verbatim} - -\chapter{\label{sec:hm}Programming with Patterns: Hindley/Milner Type Inference} - -This chapter demonstrates Scala's data types and pattern matching by -developing a type inference system in the Hindley/Milner style. The -source language for the type inferencer is lambda calculus with a let -construct. Abstract syntax trees for the source language are -represented by the following data type of \verb@Terms@. -\begin{verbatim} -abstract class Term; -case class Var(x: String) extends Term; -case class Lam(x: String, e: Term) extends Term; -case class App(f: Term, e: Term) extends Term; -case class Let(x: String, e: Term, f: Term) extends Term; -\end{verbatim} -There are four tree constructors: \verb@Var@ for variables, \verb@Lam@ -for function abstractions, \verb@App@ for function applications, and -\verb@Let@ for let expressions. Note that these tree constructors are -defined outside the \verb@Term@ class. It would also be possible -to define further constructors for this type in other parts of the -program. - -The next data type describes the form of types that are -computed by the inference system. -\begin{verbatim} -module Types { - abstract final class Type; - case class Tyvar(a: String) extends Type; - case class Arrow(t1: Type, t2: Type) extends Type; - case class Tycon(k: String, ts: List[Type]) extends Type; - private var n: int = 0; - def newTyvar: Type = { n = n + 1 ; Tyvar("a" + n) } -} -import Types; -\end{verbatim} -There are three type constructors: \verb@Tyvar@ for type variables, -\verb@Arrow@ for function types and \verb@Tycon@ for type -constructors such as \verb@boolean@ or \verb@List@. Type constructors -have as component a list of their type parameters. This list is empty -for type constants such as \verb@boolean@. The data type is packaged -in a module \verb@Types@. Also contained in that module is a function -\verb@newTyvar@ which creates a fresh type variable each time it is -called. The module definition is followed by an import clause -\verb@import Types@, which makes the non-private members of -this module available without qualification in the code that follows. - -Note that \verb@Type@ is a \verb@final@ class. This means that no -subclasses or data constructors that extend \verb@Type@ can be formed -except for the three constructors that follow the class. This makes -\verb@Type@ into a {\em closed} algebraic data type with a fixed -number of alternatives. By contrast, type \verb@Term@ is an {\em open} -algebraic type for which further alternatives can be defined. - -The next data type describes type schemes, which consist of a type and -a list of names of type variables which appear universally quantified -in the type scheme. For instance, the type scheme $\forall a\forall -b.a \arrow b$ would be represented in the type checker as: -\begin{verbatim} -TypeScheme(["a", "b"], Arrow(Tyvar("a"), Tyvar("b"))) . -\end{verbatim} -The data type definition of type schemes does not carry an extends -clause; this means that type schemes extend directly class -\verb@Object@. -Even though there is only one possible way to construct a type scheme, -a \verb@case class@ representation was chosen since it offers a convenient -way to decompose a type scheme into its parts using pattern matching. -\begin{verbatim} -case class TypeScheme(ls: List[String], t: Type) { - def newInstance: Type = { - val instSubst = - ((EmptySubst: Subst) :_foldl ls) { s, a => s.extend(Tyvar(a), newTyvar) } - instSubst(t) - } -} -\end{verbatim} -Type scheme objects come with a method \verb@newInstance@, which -returns the type contained in the scheme after all universally type -variables have been renamed to fresh variables. - -The next class describes substitutions. A substitution is an -idempotent function from type variables to types. It maps a finite -number of given type variables to given types, and leaves all other -type variables unchanged. The meaning of a substitution is extended -point-wise to a mapping from types to types. - -\begin{verbatim} -abstract class Subst extends Function1[Type,Type] { - def lookup(x: Tyvar): Type; - def apply(t: Type): Type = t match { - case Tyvar(a) => val u = lookup(Tyvar(a)); if (t == u) t else apply(u); - case Arrow(t1, t2) => Arrow(apply(t1), apply(t2)) - case Tycon(k, ts) => Tycon(k, ts map apply) - } - def extend(x: Tyvar, t: Type) = new Subst { - def lookup(y: Tyvar): Type = if (x == y) t else outer.lookup(y); - } -} -case class EmptySubst extends Subst { def lookup(t: Tyvar): Type = t } -\end{verbatim} -We represent substitutions as functions, of type -\verb@Type => Type@. To be an instance of this type, a -substitution \verb@s@ has to implement an \verb@apply@ method that takes a -\verb@Type@ as argument and yields another \verb@Type@ as result. A function -application \verb@s(t)@ is then interpreted as \verb@s.apply(t)@. - -The \verb@lookup@ method is abstract in class \verb@Subst@. Concrete -substitutions are defined by the case class \verb@EmptySubst@ and the -method \verb@extend@ in class \verb@Subst@. - -The next class gives a naive implementation of sets using lists as the -implementation type. It implements methods \verb@contains@ for -membership tests as well as \verb@union@ and \verb@diff@ for set union -and difference. Alternatively, one could have used a more efficient -implementation of sets in some standard library. -\begin{verbatim} -class ListSet[a](xs: List[a]) { - val elems: List[a] = xs; - - def contains(y: a): boolean = xs match { - case [] => false - case x :: xs1 => (x == y) || (xs1 contains y) - } - - def union(ys: ListSet[a]): ListSet[a] = xs match { - case [] => ys - case x :: xs1 => - if (ys contains x) ListSet(xs1) union ys - else ListSet(x :: (ListSet(xs1) union ys).elems) - } - - def diff(ys: ListSet[a]): ListSet[a] = xs match { - case [] => ListSet([]) - case x :: xs1 => - if (ys contains x) ListSet(xs1) diff ys - else ListSet(x :: (ListSet(xs1) diff ys).elems) - } -} -\end{verbatim} - -We now present the type checker module. The type checker -computes a type for a given term in a given environment. Environments -associate variable names with type schemes. They are represented by a -type alias \verb@Env@ in module \verb@TypeChecker@: -\begin{verbatim} -module TypeChecker { - - /** Type environments are lists of bindings that associate a - * name with a type scheme. - */ - type Env = List[(String, TypeScheme)]; -\end{verbatim} -There is also an exception \verb@TypeError@, which is thrown when type -checking fails. Exceptions are modeled as case classes that inherit -from the predefined \verb@Exception@ class. -\begin{verbatim} - case class TypeError(msg: String) extends Exception(msg); -\end{verbatim} -The \verb@Exception@ class defines a \verb@throw@ method which causes -the exception to be thrown. - -The \verb@TypeChecker@ module contains several utility -functions. Function -\verb@tyvars@ yields the set of free type variables of a type, -of a type scheme, of a list of types, or of an environment. Its -implementation is as four overloaded functions, one for each type of -argument. -\begin{verbatim} - def tyvars(t: Type): ListSet[String] = t match { - case Tyvar(a) => new ListSet([a]) - case Arrow(t1, t2) => tyvars(t1) union tyvars(t2) - case Tycon(k, ts) => tyvars(ts) - } - def tyvars(ts: TypeScheme): ListSet[String] = ts match { - case TypeScheme(as, t) => tyvars(t) diff new ListSet(as) - } - def tyvars(ts: List[Type]): ListSet[String] = ts match { - case [] => new ListSet[String]([]) - case t :: ts1 => tyvars(t) union tyvars(ts1) - } - def tyvars(env: Env): ListSet[String] = env match { - case [] => new ListSet[String]([]) - case (x, t) :: env1 => tyvars(t) union tyvars(env1) - } -\end{verbatim} -The next utility function, \verb@lookup@, returns the type scheme -associated with a given variable name in the given environment, or -returns \verb@null@ if no binding for the variable exists in the environment. -\begin{verbatim} - def lookup(env: Env, x: String): TypeScheme = env match { - case [] => null - case (y, t) :: env1 => if (x == y) t else lookup(env1, x) - } -\end{verbatim} -The next utility function, \verb@gen@, returns the type scheme that -results from generalizing a given type in a given environment. This -means that all type variables that occur in the type but not in the -environment are universally quantified. -\begin{verbatim} - def gen(env: Env, t: Type): TypeScheme = - TypeScheme((tyvars(t) diff tyvars(env)).elems, t); -\end{verbatim} -The next utility function, \verb@mgu@, computes the most general -unifier of two given types $t$ and $u$ under a pre-existing -substitution $s$. That is, it returns the most general -substitution $s'$ which extends $s$, and which makes $s'(t)$ and -$s'(u)$ equal types. The function throws a \verb@TypeError@ exception -if no such substitution exists. This can happen because the two types -have different type constructors at corresponding places, or because -a type variable is unified with a type that contains the type variable -itself. -\begin{verbatim} - def mgu(t: Type, u: Type)(s: Subst): Subst = (s(t), s(u)) match { - case (Tyvar( a), Tyvar(b)) if a == b => - s - case (Tyvar(a), _) => - if (tyvars(u) contains a) - TypeError("unification failure: occurs check").throw - else s.extend(Tyvar(a), u) - case (_, Tyvar(a)) => - mgu(u, t)(s) - case (Arrow(t1, t2), Arrow(u1, u2)) => - mgu(t1, u1)(mgu(t2, u2)(s)) - case (Tycon(k1, ts), Tycon(k2, us)) if k1 == k2 => - (s :_foldl ((ts zip us) map (case (t,u) => mgu(t,u)))) { s, f => f(s) } - case _ => TypeError("unification failure").throw - } -\end{verbatim} -The main task of the type checker is implemented by function -\verb@tp@. This function takes as first parameters an environment $env$, a -term $e$ and a proto-type $t$. As a second parameter it takes a -pre-existing substitution $s$. The function yields a substitution -$s'$ that extends $s$ and that -turns $s'(env) \ts e: s'(t)$ into a derivable type judgment according -to the derivation rules of the Hindley/Milner type system \cite{hindley-milner}. A -\verb@TypeError@ exception is thrown if no such substitution exists. -\begin{verbatim} - def tp(env: Env, e: Term, t: Type)(s: Subst): Subst = e match { - case Var(x) => { - val u = lookup(env, x); - if (u == null) TypeError("undefined: x").throw - else mgu(u.newInstance, t)(s) - } - case Lam(x, e1) => { - val a = newTyvar, b = newTyvar; - val s1 = mgu(t, Arrow(a, b))(s); - val env1 = (x, TypeScheme([], a)) :: env; - tp(env1, e1, b)(s1) - } - case App(e1, e2) => { - val a = newTyvar; - val s1 = tp(env, e1, Arrow(a, t))(s); - tp(env, e2, a)(s1) - } - case Let(x, e1, e2) => { - val a = newTyvar; - val s1 = tp(env, e1, a)(s); - tp((x, gen(env, s1(a))) :: env, e2, t)(s1) - } - } -\end{verbatim} -The next function, \verb@typeOf@ is a simplified facade for -\verb@tp@. It computes the type of a given term $e$ in a given -environment $env$. It does so by creating a fresh type variable \verb$a$, -computing a typing substitution that makes \verb@env $\ts$ e: a@ into -a derivable type judgment, and finally by returning the result of -applying the substitution to $a$. -\begin{verbatim} - def typeOf(env: Env, e: Term): Type = { - val a = newTyvar; - tp(env, e, a)(EmptySubst)(a) - } -} -\end{verbatim} -This concludes the presentation of the type inference system. -To apply the system, it is convenient to have a predefined environment -that contains bindings for commonly used constants. The module -\verb@Predefined@ defines an environment \verb@env@ that contains -bindings for booleans, numbers and lists together with some primitive -operations over these types. It also defines a fixed point operator -\verb@fix@, which can be used to represent recursion. -\begin{verbatim} -module Predefined { - val booleanType = Tycon("Boolean", []); - val intType = Tycon("Int", []); - def listType(t: Type) = Tycon("List", [t]); - - private def gen(t: Type): TypeScheme = TypeChecker.gen([], t); - private val a = newTyvar; - val env = [ - ("true", gen(booleanType)), - ("false", gen(booleanType)), - ("$\mbox{\prog{if}}$", gen(Arrow(booleanType, Arrow(a, Arrow(a, a))))), - ("zero", gen(intType)), - ("succ", gen(Arrow(intType, intType))), - ("$\mbox{\prog{nil}}$", gen(listType(a))), - ("cons", gen(Arrow(a, Arrow(listType(a), listType(a))))), - ("isEmpty", gen(Arrow(listType(a), booleanType))), - ("head", gen(Arrow(listType(a), a))), - ("tail", gen(Arrow(listType(a), listType(a)))), - ("fix", gen(Arrow(Arrow(a, a), a))) - ]; -} -\end{verbatim} -Here's an example how the type inferencer is used. -Let's define a function \verb@showType@ which returns the type of -a given term computed in the predefined environment -\verb@Predefined.env@: -\begin{verbatim} -> def showType(e: Term) = TypeChecker.typeOf(Predefined.env, e); -\end{verbatim} -Then the application -\begin{verbatim} -> showType(Lam("x", App(App(Var("cons"), Var("x")), Var("$\mbox{\prog{nil}}$")))); -\end{verbatim} -would give the response -\begin{verbatim} -> TypeScheme([a0], Arrow(Tyvar(a0), Tycon("List", [Tyvar(a0)]))); -\end{verbatim} - -\exercise -Add \verb@toString@ methods to the data constructors of class -\verb@Type@ and \verb@TypeScheme@ which represent types in a more -natural way. - -\chapter{Abstractions for Concurrency}\label{sec:ex-concurrency} - -This section reviews common concurrent programming patterns and shows -how they can be implemented in Scala. - -\section{Signals and Monitors} - -\example -The {\em monitor} provides the basic means for mutual exclusion -of processes in Scala. It is defined as follows. -\begin{verbatim} -class Monitor { - def synchronized [a] (def e: a): a; -} -\end{verbatim} -The \verb@synchronized@ method in class \verb@Monitor@ executes its -argument computation \verb@e@ in mutual exclusive mode -- at any one -time, only one thread can execute a \verb@synchronized@ argument of a -given monitor. - -Threads can suspend inside a monitor by waiting on a signal. The -\verb@Signal@ class offers two methods \verb@send@ and -\verb@wait@. Threads that call the \verb@wait@ method wait until a -\verb@send@ method of the same signal is called subsequently by some -other thread. Calls to \verb@send@ with no threads waiting for the -signal are ignored. Here is the specification of the \verb@Signal@ -class. -\begin{verbatim} -class Signal { - def wait: unit; - def wait(msec: long): unit; - def notify: unit; - def notifyAll: unit; -} -\end{verbatim} -A signal also implements a timed form of \verb@wait@, which blocks -only as long as no signal was received or the specified amount of time -(given in milliseconds) has elapsed. Furthermore, there is a -\verb@notifyAll@ method which unblocks all threads which wait for the -signal. \verb@Signal@ and \verb@Monitor@ are primitive classes in -Scala which are implemented in terms of the underlying runtime system. - -As an example of how monitors and signals are used, here is is an -implementation of a bounded buffer class. -\begin{verbatim} -class BoundedBuffer[a](N: int) extends Monitor { - var in = 0, out = 0, n = 0; - val elems = new Array[a](N); - val nonEmpty = new Signal; - val nonFull = new Signal; -\end{verbatim} -\begin{verbatim} - def put(x: a) = synchronized { - if (n == N) nonFull.wait; - elems(in) = x ; in = (in + 1) % N ; n = n + 1; - if (n == 1) nonEmpty.send; - } -\end{verbatim} -\begin{verbatim} - def get: a = synchronized { - if (n == 0) nonEmpty.wait - val x = elems(out) ; out = (out + 1) % N ; n = n - 1; - if (n == N - 1) nonFull.send; - x - } -} -\end{verbatim} -And here is a program using a bounded buffer to communicate between a -producer and a consumer process. -\begin{verbatim} -val buf = new BoundedBuffer[String](10) -fork { while (true) { val s = produceString ; buf.put(s) } } -fork { while (true) { val s = buf.get ; consumeString(s) } } -\end{verbatim} -The \verb@fork@ method spawns a new thread which executes the -expression given in the parameter. It can be defined as follows. -\begin{verbatim} -def fork(def e: unit) = { - val p = new Thread { def run = e; } - p.run -} -\end{verbatim} - -\comment{ -\section{Logic Variable} - -A logic variable (or lvar for short) offers operations \verb@:=@ -and \verb@value@ to define the variable and to retrieve its value. -Variables can be \verb@define@d only once. A call to \verb@value@ -blocks until the variable has been defined. - -Logic variables can be implemented as follows. - -\begin{verbatim} -class LVar[a] extends Monitor { - private val defined = new Signal - private var isDefined: boolean = false - private var v: a - def value = synchronized { - if (!isDefined) defined.wait - v - } - def :=(x: a) = synchronized { - v = x ; isDefined = true ; defined.send - } -} -\end{verbatim} -} - -\section{SyncVars} - -A synchronized variable (or syncvar for short) offers \verb@get@ and -\verb@put@ operations to read and set the variable. \verb@get@ operations -block until the variable has been defined. An \verb@unset@ operation -resets the variable to undefined state. - -Synchronized variables can be implemented as follows. -\begin{verbatim} -class SyncVar[a] extends Monitor { - private val defined = new Signal; - private var isDefined: boolean = false; - private var value: a; - def get = synchronized { - if (!isDefined) defined.wait; - value - } - def set(x: a) = synchronized { - value = x ; isDefined = true ; defined.send; - } - def isSet: boolean = - isDefined; - def unset = synchronized { - isDefined = false; - } -} -\end{verbatim} - -\section{Futures} -\label{sec:futures} - -A {\em future} is a value which is computed in parallel to some other -client thread, to be used by the client thread at some future time. -Futures are used in order to make good use of parallel processing -resources. A typical usage is: - -\begin{verbatim} -val x = future(someLengthyComputation); -anotherLengthyComputation; -val y = f(x()) + g(x()); -\end{verbatim} - -Futures can be implemented in Scala as follows. - -\begin{verbatim} -def future[a](def p: a): unit => a = { - val result = new SyncVar[a]; - fork { result.set(p) } - (=> result.get) -} -\end{verbatim} - -The \verb@future@ method gets as parameter a computation \verb@p@ to -be performed. The type of the computation is arbitrary; it is -represented by \verb@future@'s type parameter \verb@a@. The -\verb@future@ method defines a guard \verb@result@, which takes a -parameter representing the result of the computation. It then forks -off a new thread that computes the result and invokes the -\verb@result@ guard when it is finished. In parallel to this thread, -the function returns an anonymous function of type \verb@a@. -When called, this functions waits on the result guard to be -invoked, and, once this happens returns the result argument. -At the same time, the function reinvokes the \verb@result@ guard with -the same argument, so that future invocations of the function can -return the result immediately. - -\section{Parallel Computations} - -The next example presents a function \verb@par@ which takes a pair of -computations as parameters and which returns the results of the computations -in another pair. The two computations are performed in parallel. - -\begin{verbatim} -def par[a, b](def xp: a, def yp: b): (a, b) = { - val y = new SyncVar[a]; - fork { y.set(yp) } - (xp, y) -} -\end{verbatim} - -The next example presents a function \verb@replicate@ which performs a -number of replicates of a computation in parallel. Each -replication instance is passed an integer number which identifies it. - -\begin{verbatim} -def replicate(start: int, end: int)(def p: int => unit): unit = { - if (start == end) { - } else if (start + 1 == end) { - p(start) - } else { - val mid = (start + end) / 2; - par ( replicate(start, mid)(p), replicate(mid, end)(p) ) - } -} -\end{verbatim} - -The next example shows how to use \verb@replicate@ to perform parallel -computations on all elements of an array. - -\begin{verbatim} -def parMap[a,b](f: a => b, xs: Array[a]): Array[b] = { - val results = new Array[b](xs.length); - replicate(0, xs.length) { i => results(i) = f(xs(i)) } - results -} -\end{verbatim} - -\section{Semaphores} - -A common mechanism for process synchronization is a {\em lock} (or: -{\em semaphore}). A lock offers two atomic actions: \prog{acquire} and -\prog{release}. Here's the implementation of a lock in Scala: - -\begin{verbatim} -class Lock extends Monitor with Signal { - var available = true; - def acquire = { - if (!available) wait; - available = false - } - def release = { - available = true; - notify - } -} -\end{verbatim} - -\section{Readers/Writers} - -A more complex form of synchronization distinguishes between {\em -readers} which access a common resource without modifying it and {\em -writers} which can both access and modify it. To synchronize readers -and writers we need to implement operations \prog{startRead}, \prog{startWrite}, -\prog{endRead}, \prog{endWrite}, such that: -\begin{itemize} -\item there can be multiple concurrent readers, -\item there can only be one writer at one time, -\item pending write requests have priority over pending read requests, -but don't preempt ongoing read operations. -\end{itemize} -The following implementation of a readers/writers lock is based on the -{\em message space} concept (see Section~\ref{sec:messagespace}). - -\begin{verbatim} -class ReadersWriters { - val m = new MessageSpace; - private case class Writers(n: int), Readers(n: int); - Writers(0); Readers(0); - def startRead = m receive { - case Writers(n) if n == 0 => m receive { - case Readers(n) => Writers(0) ; Readers(n+1); - } - } - def startWrite = m receive { - case Writers(n) => - Writers(n+1); - m receive { case Readers(n) if n == 0 => } - } -\end{verbatim} -\begin{verbatim} - def endRead = receive { - case Readers(n) => Readers(n-1) - } - def endWrite = receive { - case Writers(n) => Writers(n-1) ; if (n == 0) Readers(0) - } -} -\end{verbatim} - -\section{Asynchronous Channels} - -A fundamental way of interprocess communication is the asynchronous -channel. Its implementation makes use the following class for linked -lists: -\begin{verbatim} -class LinkedList[a](x: a) { - val elem: a = x; - var next: LinkedList[a] = null; -} -\end{verbatim} -To facilitate insertion and deletion of elements into linked lists, -every reference into a linked list points to the node which precedes -the node which conceptually forms the top of the list. -Empty linked lists start with a dummy node, whose successor is \verb@null@. - -The channel class uses a linked list to store data that has been sent -but not read yet. In the opposite direction, a signal \verb@moreData@ is -used to wake up reader threads that wait for data. -\begin{verbatim} -class Channel[a] { - private val written = new LinkedList[a](null); - private var lastWritten = written; - private val moreData = new Signal; - - def write(x: a) = { - lastWritten.next = new LinkedList(x); - lastWritten = lastWritten.next; - moreData.notify; - } - - def read: a = { - if (written.next == null) moreData.wait; - written = written.next; - written.elem; - } -} -\end{verbatim} - -\section{Synchronous Channels} - -Here's an implementation of synchronous channels, where the sender of -a message blocks until that message has been received. Synchronous -channels only need a single variable to store messages in transit, but -three signals are used to coordinate reader and writer processes. -\begin{verbatim} -class SyncChannel[a] { - val data = new SyncVar[a]; - - def write(x: a): unit = synchronized { - val empty = new Signal, full = new Signal, idle = new Signal; - if (data.isSet) idle.wait; - data.put(x); - full.send; - empty.wait; - data.unset; - idle.send; - } - - def read: a = synchronized { - if (!(data.isSet)) full.wait; - x = data.get; - empty.send; - x - } -} -\end{verbatim} - -\section{Workers} - -Here's an implementation of a {\em compute server} in Scala. The -server implements a \verb@future@ method which evaluates a given -expression in parallel with its caller. Unlike the implementation in -Section~\ref{sec:futures} the server computes futures only with a -predefined number of threads. A possible implementation of the server -could run each thread on a separate processor, and could hence avoid -the overhead inherent in context-switching several threads on a single -processor. - -\begin{verbatim} -class ComputeServer(n: int) { - private abstract class Job { - abstract type t; - def task: t; - def return(x: t): unit; - } - - private val openJobs = new Channel[Job] - - private def processor: unit = { - while (true) { - val job = openJobs.read; - job.return(job.task) - } - } -\end{verbatim} -\begin{verbatim} - def future[a](def p: a): () => a = { - val reply = new SyncVar[a]; - openJobs.write( - new Job { - type t = a; - def task = p; - def return(x: a) = reply.set(x); - } - ) - (=> reply.get) - } - - replicate(n){processor}; -} -\end{verbatim} - -Expressions to be computed (i.e. arguments -to calls of \verb@future@) are written to the \verb@openJobs@ -channel. A {\em job} is an object with -\begin{itemize} -\item -An abstract type \verb@t@ which describes the result of the compute -job. -\item -A parameterless \verb@task@ method of type \verb@t@ which denotes -the expression to be computed. -\item -A \verb@return@ method which consumes the result once it is -computed. -\end{itemize} -The compute server creates $n$ \verb@processor@ processes as part of -its initialization. Every such process repeatedly consumes an open -job, evaluates the job's \verb@task@ method and passes the result on -to the job's -\verb@return@ method. The polymorphic \verb@future@ method creates -a new job where the \verb@return@ method is implemented by a guard -named \verb@reply@ and inserts this job into the set of open jobs by -calling the \verb@isOpen@ guard. It then waits until the corresponding -\verb@reply@ guard is called. - -The example demonstrates the use of abstract types. The abstract type -\verb@t@ keeps track of the result type of a job, which can vary -between different jobs. Without abstract types it would be impossible -to implement the same class to the user in a statically type-safe -way, without relying on dynamic type tests and type casts. - -\section{Message Spaces} -\label{sec:messagespace} - -Message spaces are high-level, flexible constructs for process -synchronization and communication. A {\em message} in this context is -an arbitrary object. There is a special message \verb@TIMEOUT@ which -is used to signal a time-out. -\begin{verbatim} -case class TIMEOUT; -\end{verbatim} -Message spaces implement the following signature. -\begin{verbatim} -class MessageSpace { - def send(msg: Any): unit; - def receive[a](f: PartialFunction[Any, a]): a; - def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a; -} -\end{verbatim} -The state of a message space consists of a multi-set of messages. -Messages are added to the space using the \verb@send@ method. Messages -are removed using the \verb@receive@ method, which is passed a message -processor \verb@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 \verb@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. - -As a simple example of how message spaces are used, consider a -one-place buffer: -\begin{verbatim} -class OnePlaceBuffer { - private val m = new MessageSpace; \=// An internal message space - private case class Empty, Full(x: int); \>// Types of messages we deal with - - m send Empty; \>// Initialization - - def write(x: int): unit = - m receive { case Empty => m send Full(x) } - - def read: int = - m receive { case Full(x) => m send Empty ; x } -} -\end{verbatim} -Here's how the message space class can be implemented: -\begin{verbatim} -class MessageSpace { - - private abstract class Receiver extends Signal { - def isDefined(msg: Any): boolean; - var msg = null; - } -\end{verbatim} -We define an internal class for receivers with a test method -\verb@isDefined@, which indicates whether the receiver is -defined for a given message. The receiver inherits from class -\verb@Signal@ a \verb@notify@ method which is used to wake up a -receiver thread. When the receiver thread is woken up, the message it -needs to be applied to is stored in the \verb@msg@ variable of -\verb@Receiver@. -\begin{verbatim} - private val sent = new LinkedList[Any](null) ; - private var lastSent = sent; - private var receivers = new LinkedList[Receiver](null); - private var lastReceiver = receivers; -\end{verbatim} -The message space class maintains two linked lists, -one for sent but unconsumed messages, the other for waiting receivers. -\begin{verbatim} - def send(msg: Any): unit = synchronized { - var r = receivers, r1 = r.next; - while (r1 != null && !r1.elem.isDefined(msg)) { - r = r1; r1 = r1.next; - } - if (r1 != null) { - r.next = r1.next; r1.elem.msg = msg; r1.elem.notify; - } else { - l = new LinkedList(msg); lastSent.next = l; lastSent = l; - } - } -\end{verbatim} -The \verb@send@ method first checks whether a waiting receiver is - -applicable to the sent message. If yes, the receiver is notified. -Otherwise, the message is appended to the linked list of sent messages. -\begin{verbatim} - def receive[a](f: PartialFunction[Any, a]): a = { - val msg: Any = synchronized { - var s = sent, s1 = s.next; - while (s1 != null && !f.isDefined(s1.elem)) { - s = s1; s1 = s1.next - } - if (s1 != null) { - s.next = s1.next; s1.elem - } else { - val r = new LinkedList( - new Receiver { - def isDefined(msg: Any) = f.isDefined(msg); - }); - lastReceiver.next = r; lastReceiver = r; - r.elem.wait; - r.elem.msg - } - } - f(msg) - } -\end{verbatim} -The \verb@receive@ method first checks whether the message processor function -\verb@f@ can be applied to a message that has already been sent but that -was not yet consumed. If yes, the thread continues immediately by -applying \verb@f@ to the message. Otherwise, a new receiver is created -and linked into the \verb@receivers@ list, and the thread waits for a -notification on this receiver. Once the thread is woken up again, it -continues by applying \verb@f@ to the message that was stored in the receiver. - -The message space class also offers a method \verb@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 \verb@TIMEOUT@ message. The implementation of -\verb@receiveWithin@ is quite similar to \verb@receive@: -\begin{verbatim} - def receiveWithin[a](msec: long)(f: PartialFunction[Any, a]): a = { - val msg: Any = synchronized { - var s = sent, s1 = s.next; - while (s1 != null && !f.isDefined(s1.elem)) { - s = s1; s1 = s1.next ; - } - if (s1 != null) { - s.next = s1.next; s1.elem - } else { - val r = new LinkedList( - new Receiver { - def isDefined(msg: Any) = f.isDefined(msg); - } - ) - lastReceiver.next = r; lastReceiver = r; - r.elem.wait(msec); - if (r.elem.msg == null) r.elem.msg = TIMEOUT; - r.elem.msg - } - } - f(msg) - } -} // end MessageSpace -\end{verbatim} -The only differences are the timed call to \verb@wait@, and the -statement following it. - -\section{Actors} -\label{sec:actors} - -Chapter~\ref{sec:ex-auction} sketched as a program example the -implementation of an electronic auction service. This service was -based on high-level actor processes, that work by inspecting messages -in their mailbox using pattern matching. An actor is simply a thread -whose communication primitives are those of a message space. -Actors are therefore defined by a mixin composition of threads and message spaces. -\begin{verbatim} -abstract class Actor extends Thread with MessageSpace; -\end{verbatim} - -\comment{ -As an extended example of an application that uses actors, we come -back to the auction server example of Section~\ref{sec:ex-auction}. -The following code implements: - -\begin{figure}[thb] -\begin{verbatim} -class AuctionMessage; -case class - \=Offer(bid: int, client: Process), \=// make a bid - \>Inquire(client: Process) extends AuctionMessage \>// inquire status - -class AuctionReply; -case class - \=Status(asked; int, expiration: Date), \>// asked sum, expiration date - \>BestOffer, \>// yours is the best offer - \>BeatenOffer(maxBid: int), \>// offer beaten by maxBid - \>AuctionConcluded(seller: Process, client: Process), \>// auction concluded - \>AuctionFailed \>// failed with no bids - \>AuctionOver extends AuctionReply \>// bidding is closed -\end{verbatim} -\end{figure} - -\begin{verbatim} -class Auction(seller: Process, minBid: int, closing: Date) - extends Process { - - val timeToShutdown = 36000000 // msec - val delta = 10 // bid increment -\end{verbatim} -\begin{verbatim} - def run = { - var askedBid = minBid - var maxBidder: Process = null - while (true) { - receiveWithin ((closing - Date.currentDate).msec) { - case Offer(bid, client) => { - if (bid >= askedBid) { - if (maxBidder != null && maxBidder != client) { - maxBidder send BeatenOffer(bid) - } - maxBidder = client - askedBid = bid + delta - client send BestOffer - } else client send BeatenOffer(maxBid) - } -\end{verbatim} -\begin{verbatim} - case Inquire(client) => { - client send Status(askedBid, closing) - } -\end{verbatim} -\begin{verbatim} - case TIMEOUT => { - if (maxBidder != null) { - val reply = AuctionConcluded(seller, maxBidder) - maxBidder send reply - seller send reply - } else seller send AuctionFailed - receiveWithin (timeToShutdown) { - case Offer(_, client) => client send AuctionOver ; discardAndContinue - case _ => discardAndContinue - case TIMEOUT => stop - } - } -\end{verbatim} -\begin{verbatim} - case _ => discardAndContinue - } - } - } -\end{verbatim} -\begin{verbatim} - def houseKeeping: int = { - val Limit = 100 - var nWaiting: int = 0 - receiveWithin(0) { - case _ => - nWaiting = nWaiting + 1 - if (nWaiting > Limit) { - receiveWithin(0) { - case Offer(_, _) => continue - case TIMEOUT => - case _ => discardAndContinue - } - } else continue - case TIMEOUT => - } - } -} -\end{verbatim} -\begin{verbatim} -class Bidder (auction: Process, minBid: int, maxBid: int) - extends Process { - val MaxTries = 3 - val Unknown = -1 - - var nextBid = Unknown -\end{verbatim} -\begin{verbatim} - def getAuctionStatus = { - var nTries = 0 - while (nextBid == Unknown && nTries < MaxTries) { - auction send Inquiry(this) - nTries = nTries + 1 - receiveWithin(waitTime) { - case Status(bid, _) => bid match { - case None => nextBid = minBid - case Some(curBid) => nextBid = curBid + Delta - } - case TIMEOUT => - case _ => continue - } - } - status - } -\end{verbatim} -\begin{verbatim} - def bid: unit = { - if (nextBid < maxBid) { - auction send Offer(nextBid, this) - receive { - case BestOffer => - receive { - case BeatenOffer(bestBid) => - nextBid = bestBid + Delta - bid - case AuctionConcluded(seller, client) => - transferPayment(seller, nextBid) - case _ => continue - } - - case BeatenOffer(bestBid) => - nextBid = nextBid + Delta - bid - - case AuctionOver => - - case _ => continue - } - } - } -\end{verbatim} -\begin{verbatim} - def run = { - getAuctionStatus - if (nextBid != Unknown) bid - } - - def transferPayment(seller: Process, amount: int) -} -\end{verbatim} -} -%\todo{We also need some XML examples.} -\end{document} - - - - case ([], _) => ys - case (_, []) => xs - case (x :: xs1, y :: ys1) => - if (x < y) x :: merge(xs1, ys) else y :: merge(xs, ys1) -} - -def split (xs: List[a]): (List[a], List[a]) = xs match { - case [] => ([], []) - case [x] => (x, []) - case y :: z :: xs1 => val (ys, zs) = split(xs1) ; (y :: ys, z :: zs) -} - -def sort(xs: List[a]): List[a] = { - val (ys, zs) = split(xs) - merge(sort(ys), sort(zs)) -} - - -def sort(a:Array[String]): Array[String] = { - val pivot = a(a.length / 2) - sort(a.filter(x => x < pivot)) ++ - a.filter(x => x == pivot) ++ - sort(a.filter(x => x > pivot)) -} - -def sort(a:Array[String]): Array[String] = { - - def swap (i: int, j: int): unit = { - val t = a(i) ; a(i) = a(j) ; a(j) = t - } - - def sort1(l: int, r: int): unit = { - val pivot = a((l + r) / 2) - var i = l, j = r - while (i <= r) { - while (i < r && a(i) < pivot) { i = i + 1 } - while (j > l && a(j) > pivot) { j = j - 1 } - if (i <= j) { - swap(i, j) - i = i + 1 - j = j - 1 - } - } - if (l < j) sort1(l, j) - if (j < r) sort1(i, r) - } - - sort1(0, a.length - 1) -} - -class Array[a] { - - def copy(to: Array[a], src: int, dst: int, len: int): unit - val length: int - val apply(i: int): a - val update(i: int, x: a): unit - - def filter (p: a => boolean): Array[a] = { - val temp = new Array[a](a.length) - var i = 0, j = 0 - for (i < a.length, i = i + 1) { - val x = a(i) - if (p(x)) { temp(j) = x; j = j + 1 } - } - val res = new Array[a](j) - temp.copy(res, 0, 0, j) - } - - def ++ (that: Array[a]): Array[a] = { - val a = new Array[a](this.length + that.length) - this.copy(a, 0, 0, this.length) - that.copy(a, 0, this.length, that.length) - } - -static - - def concat [a] (as: List[Array[a]]) = { - val l = (as map (a => a.length)).sum - val dst = new Array[a](l) - var j = 0 - as forall {a => { a.copy(dst, j, a.length) ; j = j + a.length }} - dst - } - -} - -module ABT extends AlgBinTree[kt, vt] -ABT.Map diff --git a/doc/reference/rationale-chapter.verb.tex b/doc/reference/rationale-chapter.verb.tex deleted file mode 100644 index 5187663f1e..0000000000 --- a/doc/reference/rationale-chapter.verb.tex +++ /dev/null @@ -1,125 +0,0 @@ -%% $Id$ - -There are hundreds of programming languages in active use, and many more are -being designed each year. It is therefore very hard to justify the development -of yet another language. Nevertheless, this is what I attempt to do here. My -argument rests on two claims: -\begin{itemize} -\item[] {\em Claim 1:} The raise in importance of web services and -other distributed software is a fundamental paradigm -shift in programming. It is comparable in scale to the shift 20 years ago -from character-oriented to graphical user interfaces. -\item[] {\em Claim 2:} That paradigm shift will provide demand -for new programming languages, just as graphical user interfaces -promoted the adoption of object-oriented languages. -\end{itemize} -To back up the first claim, one observes that web services and other -distributed software increasingly tend to communicate using structured or -semi-structured data. A typical example is the use of XML to describe data -managed by applications as well as the messages between applications. This -tends to affect the role of a program in a fundamental way. Previously, -programs could be seen as objects that reacted to method calls and in turn -called methods of other objects. Some of these method calls might originate -from users while others might originate from other computers via remote -invocations. These method calls have simple unstructured parameters or object -references as arguments. Web services, on the other hand, communicate with -each other by transmitting asynchronous messages that carry structured -documents, usually in XML format. Programs then conceptually become {\em tree -transformers} that consume incoming message documents and produce outgoing -ones. - -To back up the second claim, one notes that today's object-oriented languages -are not very good tools for analyzing and transforming the trees which -conceptually model XML data. Because these trees usually contain data but no -methods, they have to be decomposed and constructed from the ``outside'', that is -from code which is external to the tree definition itself. In an -object-oriented language, the ways of doing so are limited. The most common -solution is to represent trees in a generic way, where all tree nodes are -values of a common type. This approach is used in DOM, for instance. It -facilitates the implementation of generic traversal functions, but forces -applications to operate on a very low conceptual level, which often loses -important semantic distinctions that are present in the XML data. A -semantically more precise alternative would be to use different internal types -to model different kinds of nodes. But then tree decompositions require the use -of run-time type tests and type casts to adapt the treatment to the kind of -node encountered. Such type tests and type casts are generally not considered -good object-oriented style. They are rarely efficient, nor easy to use. By -contrast, tree transformation is the natural domain of functional -languages. Their algebraic data types, pattern matching and higher-order -functions make these languages ideal for the task. It's no wonder, then, that -specialized languages for transforming XML data such as XSLT are -functional. - -Web services can be constructed using such a transformation language -together with some middleware framework such as Corba to handle -distribution and an object-oriented language for the ``application -logic''. The downside of this approach is that the necessary amount -of cross-language glue can make applications cumbersome to write, -verify, and maintain. Better productivity and trustworthiness is -achievable using a single notation and conceptual framework that would -express object-oriented, concurrent, as well as functional aspects of -an application. Hence, a case for so called ``multi-paradigm'' -languages can be made. But one needs to be careful not to simply -replace cross-language glue by awkward interfaces between different -paradigms within the language itself. The benefits of integration are -realized fully only if the common language achieves a meaningful -unification of concepts rather than being merely an agglutination of -different programming paradigms. This is what we try to achieve with -Scala\footnote{Scala stands for ``Scalable Language''.}. - -Scala is both an an object-oriented and functional language. It is a -pure object-oriented language in the sense that every value is an -object. Types and behavior of objects are described by -classes. Classes can be composed using mixin composition. Scala is -designed to interact well with mainstream object-oriented languages, -in particular Java and C\#. - -Scala is also a functional language in the sense that every function -is a value. Nesting of function definitions and higher-order functions -are naturally supported. Scala also supports a general notion of -pattern matching which can model the algebraic types used in many -functional languages. Furthermore, this notion of pattern matching -naturally extends to the processing of XML data. - -The design of Scala is driven by the desire to unify object-oriented -and functional elements. Here are three examples how this is achieved: -\begin{itemize} -\item -Since every function is a value and every value is an object, it -follows that every function in Scala is an object. Indeed, there is a -root class for functions which is specialized in the Scala standard -library to data structures such as arrays and hash tables. -\item -Data structures in many functional languages are defined using -algebraic data types. They are decomposed using pattern matching. -Object-oriented languages, on the other hand, describe data with class -hierarchies. Algebraic data types are usually closed, in that the -range of alternatives of a type is fixed when the type is defined. By -contrast, class hierarchies can be extended by adding new leaf -classes. Scala adopts the object-oriented class hierarchy scheme for -data definitions, but allows pattern matching against values coming -from a whole class hierarchy, not just values of a single type. -This can express both closed and extensible data types, and also -provides a convenient way to exploit run-time type information in -cases where static typing is too restrictive. -\item -Module systems of functional languages such as SML or Caml excel in -abstraction; they allow very precise control over visibility of names -and types, including the ability to partially abstract over types. By -contrast, object-oriented languages excel in composition; they offer -several composition mechanisms lacking in module systems, including -inheritance and unlimited recursion between objects and classes. -Scala unifies the notions of object and module, of module signature -and interface, as well as of functor and class. This combines the -abstraction facilities of functional module systems with the -composition constructs of object-oriented languages. The unification -is made possible by means of a new type system based on path-dependent -types \cite{odersky-et-al:fool10}. -\end{itemize} - -%The rest of this report is structured as follows. Chapters -%\ref{sec:simple-examples} to \ref{sec:concurrency} give an informal overview of -%Scala by means of a sequence of program examples. The remaining -%chapters contain the language definition. The definition is formulated -%in prose but tries to be precise. - diff --git a/doc/reference/rationale.verb.tex b/doc/reference/rationale.verb.tex deleted file mode 100644 index 371e6efe19..0000000000 --- a/doc/reference/rationale.verb.tex +++ /dev/null @@ -1,21 +0,0 @@ -%% $Id$ - -\documentclass[11pt]{article} - -\usepackage{fleqn,a4wide,modefs,math,prooftree,scaladefs,vquote} - -\title{Scala Rationale \\ Why a New programming Language for Web Services?} - -\author{ -Martin Odersky -} - -\sloppy -\begin{document} -\maketitle - -%\todo{`:' as synononym for $\EXTENDS$?} - - -\input{rationale-chapter} -\end{document} \ No newline at end of file diff --git a/doc/reference/reference.verb.tex b/doc/reference/reference.verb.tex deleted file mode 100644 index dff170c2d7..0000000000 --- a/doc/reference/reference.verb.tex +++ /dev/null @@ -1,5025 +0,0 @@ -% $Id$ - -\documentclass[11pt]{report} - -\usepackage{fleqn,a4,modefs,math,prooftree,scaladefs,vquote} - -\newcommand{\ifqualified}[1]{} -\newcommand{\iflet}[1]{} -\newcommand{\ifundefvar}[1]{} -\newcommand{\iffinaltype}[1]{} -\newcommand{\ifpackaging}[1]{} -\newcommand{\ifnewfor}[1]{} -\renewcommand{\todo}[1]{{$\clubsuit$\bf todo: #1$\spadesuit$}} -\newcommand{\notyet}{\footnote{not yet implemented.}} -\title{Report on the Programming Language Scala} - -\date{\today} - -\author{ -Martin Odersky \\ -Philippe Altherr \\ -Vincent Cremet \\ -Burak Emir \\ -St\'ephane Micheloud \\ -Nikolay Mihaylov \\ -Michel Schinz \\ -Erik Stenman \\ -Matthias Zenger -\\ \ -\\ -EPFL} - - -\sloppy -\begin{document} -\maketitle - -%\todo{`:' as synonym for $\EXTENDS$?} - -\chapter{Rationale} - -\input{rationale-chapter} - -\comment{ -\chapter{Change Log} - -5 August 2001: Changed from join patterns in function definitions to -when clauses. - -5 August 2001: Introduced guard part in case expressions. - -5 August 2001: Dropped overload modifier. - -5 August 2001: Dropped \verb@=>@ as an alternative for \verb@=@ in -definitions. - -5 August 2001: Dropped \verb@nil@ type. - -5 August Replaced \verb@&@ operator for parallel composition by -\verb@fork@ function. - -5 August 2001: Added chapter on Concurrency (\sref{sec:concurrency}). - -7 August 2001: Made explicit in the grammar that block-local -definitions do not have modifiers. - -7 August 2001: Introduced permitted but redundant modifier `private' -for guards. - -9 August 2001: Replaced qualified identifiers in class definitions by -modifiers \verb@new@ and \verb@override@. - -9 August 2001: Tightened rules for member access, so that superclass -ordering is irrelevant. See definition of qualified expansion in -\sref{sec:names}. - -9 August 2001: Guarded choice now always picks tectually first enabled -guard, rather than an arbitrary one. - -16 August 2001: Unary postfix operators now have lower precedence than -unary infix. - -16 August 2001: Use `=' instead of `:=' for assignment. - -16 August 2001: Changed scope rules so that scope of a definition -always extends to the whole enclosing block or template, plus an -anti forward-dependency rule for value definitions. - -16 August 2001: Changed Grammar to allow repeated data definitions -only with extends clauses of simple type, so that parameter names -cannot be used. - -16 August 2001: Changed Grammar to drop NxStat, etc (the context-free language -is not affected by the change). - -23 August 2001: Eliminated unboxed types. - -23 August 2001: Eliminated recursive value definitions; changed rules - for pattern value definitions. - -26 August 2001: Clarified indentation rules. - -26 August 2001: Adapted meaning of \verb@null@ to value types. - -26 August 2001: Apply local type inference in class instance expressions. - -23 Sep 2001: Changed $\arrow$ in closures to $\Arrow$. - -23 Sep 2001: Changed record types to refinements. - -25 Oct 2001: Simplified and generalized class and module -design. Classes and modules can now appear anywhere; modules are no -longer parameterized. - -25 Oct 2001: Dropped aspects (for the time being). - -29 Oct 2001: - Tuple and function types are now shorthands for predefined - classes. Tuples are no longer covariant. - -29 Oct 2001: - Introduced $n$-ary functions and changed syntax for function types. - -29 Oct 2001: - Dropped static part of classes. Classes now define a constructor - function of the same name. - -29 Oct 2001: - Generalized rules for overloading slightly. - -29 Oct 2001: - Dropped modifiers for guards. - -29 Oct 2001: - Disambiguated syntax for pattern matching cases with guards. -class P[+a, +b] { - val fst: a, snd: b -} - -2 Nov 2001: Changed private and protected to their meaning in Java. - -2 Nov 2001: Introduced packagings. - -5 Nov 2001: Dropped value parameters in class aliases. - -14 Nov 2001: Fixed rule for subtyping of overloaded -function. Tightened scope of value parameters. - -15 Nov 2001: Changed `with' to `if' as pattern guard and simplified -pattern syntax. - -15 Nov 2001: Changed `data' to `case class'. - -20 Nov 2001: Case classes need no longer be `final'. - -30 Nov 2001: Introduced `qualified' classes, with unqualified classes -being the default. - -4 Dec 2001: Introduced interfaces (\sref{sec:interfaces}) - -4 Dec 2001: Changed rules which members are inherited (\sref{sec:members}). - -4 Dec 2001: Changed rules for compound types with refinements to match -those for templates (\sref{sec:compound-types}). - -6 Dec 2001: Dropped modifiers `virtual' and `new'. - -6 Dec 2001: `new' is again mandatory in instance creation expressions. - -10 Dec 2001: Dropped concurrency constructs in language. - -11 Dec 2001: Changed name from `Funnel' to `Scala'. - -18 Dec 2001: Slight change of syntax for anonymous functions. - -29 Dec 2001: Case classes define accessors for parameters - -6 Feb 2002: Import clauses defined only for stable identifiers. - -6 Feb 2002: Dropped restriction that classes may not have -inherited abstract members. - -6 Feb 2002: Reclassified `new' as Expr4 - -6 Feb 2002: Dropped interface keyword - -6 Feb 2002: Changed syntax of `if'. - -6 Feb 2002: Introduced constructor types. - -6 Feb 2002: Eliminated class aliases. - -6 Feb 2002: Replaced user-defined value definitions by comprehensions. - -6 Feb 2002: Tightened conditions on well-formed base class sequence. - -6 Feb 2002: Changed root class hierarchy. - -7 Feb 2002: Tightened rules on forward references. - -7 Feb 2002: Only prefix operators are now `-', `+', `!'. They are -translated to method calls of their operand. -} - -class List[a <: AnyRef](x: a, xs: List[a]) { - def head = x; - def tail = xs; - def this(x: a) = { ... ; this(x, Nil); ... } - def this() = this(null, Nil); -} - - - - -% 16 Jul 2003 Regular pattern matching (Chapter 8) - -\subsection*{Status of This Document} - -The present document defines slightly more than what is implemented in -the current compiler. But I have tried to mark all omissions that -still exist. - -\part{Language Definition} - -\chapter{Lexical Syntax} - -This chapter defines the syntax of Scala tokens. Tokens are -constructed from symbols in the following character sets: -\begin{enumerate} -\item Whitespace characters. -\item Lower case letters \verb@`a' | ... | `z'@ and -upper case letters \verb@`A' | ... | `Z' | `$\Dollar$' | `_'@. -\item Digits \verb@`0' | ... | `9'@. -\item Parentheses \verb@`(' | `)' | `[' | `]' | `{' | `}'@. -\item Delimiter characters \verb@`\' | `'' | `"' | `.' | `;' | `,'@. -\item Operator characters. These include all printable ASCII characters -which are in none of the sets above. -\end{enumerate} - -These sets are extended in the usual way to unicode\notyet (i.e.\ as in Java). -Unicode encodings \verb@`\uXXXX'@ are also as in Java. - -\section{Identifiers} - -\syntax\begin{verbatim} -op \=::= \= special {special} [`_' [id]] -varid \>::= \> lower {letter $|$ digit} [`_' [id]] -id \>::= \> upper {letter $|$ digit} [`_' [id]] - \> | \> varid - \> | \> op -\end{verbatim} - -There are two ways to form an identifier. First, an identifier can -start with a letter which can be followed by an arbitrary sequence of -letters and digits. Second, an identifier can be start with a special -character followed by an arbitrary sequence of special characters. -In both cases, the identifier prefix may be immediately followed -by an underscore `\verb@_@' character and another string of characters -that by themselves make up an identifier. As usual, a longest match -rule applies. For instance, the string - -\begin{verbatim} -big_bob++=z3 -\end{verbatim} - -decomposes into the three identifiers \verb@big_bob@, \verb@++=@, and -\verb@z3@. The rules for pattern matching further distinguish between -{\em variable identifiers}, which start with a lower case letter, and -{\em constant identifiers}, which do not. - - -The `\verb@\$@' character is reserved for compiler-synthesized identifiers. -User programs are not allowed to define identifiers which contain `\verb@\$@' -characters. - -The following names are reserved words instead of being members of the -syntactic class \verb@id@ of lexical identifiers. - -\begin{verbatim} -abstract case catch class def -do else extends false final -finally for if import new -null object override package private -protected return sealed super this -trait try true type val -var while with yield -_ : = => <- <: >: # @ -\end{verbatim} - -The unicode operator `\verb@=>@' has the ascii equivalent -`$=>$', which is also reserved\notyet. - -\example -Here are examples of identifiers: -\begin{verbatim} - x \=Object \=maxIndex \=p2p \=empty_? - + \> +_field -\end{verbatim} - -\section{Braces and Semicolons} - -A semicolon `\verb@;@' is implicitly inserted after every closing brace -if there is a new line character between closing brace and the next -regular token after it, except if that token cannot legally start a -statement. - -The tokens which cannot legally start a statement -are the following delimiters and reserved words: -\begin{verbatim} -else extends with yield do -, . ; : = => <- <: >: # @ ) ] } -\end{verbatim} - -\section{Literals} - -There are literals for integer numbers (of types \verb@Int@ and \verb@Long@), -floating point numbers (of types \verb@Float@ and \verb@Double@), characters, and -strings. The syntax of these literals is in each case as in Java. - -\syntax\begin{verbatim} -literal \=::= \= intLit - \> | \> floatLit - \> | \> charLit - \> | \> stringLit - \> | \> symbolLit -intLit \>::= \> ``as in Java'' -floatLit \>::= \> ``as in Java'' -charLit \>::= \> ``as in Java'' -stringLit \>::= \> ``as in Java'' -symbolLit ::= `\'` id -\end{verbatim} - -A symbol literal has the form \verb@'x@ where \verb@x@ is an identifier. -Such a symbol literal is a shorthand for the application -\begin{verbatim} -scala.Symbol("x") -\end{verbatim} -of the facotry method for the standard case class \verb@Symbol@ to the string "x". - -\section{Whitespace and Comments} - -Tokens may be separated by whitespace characters (ascii codes 0 to 32) -and/or comments. Comments come in two forms: - -A single-line comment is a sequence of characters which starts with -\verb@//@ and extends to the end of the line. - -A multi-line comment is a sequence of characters between \verb@/*@ and -\verb@*/@. Multi-line comments may be nested. - - -\chapter{\label{sec:names}Identifiers, Names and Scopes} - -Names in Scala identify types, values, functions, and classes which -are collectively called {\em entities}. Names are introduced by -definitions, declarations (\sref{sec:defs}) or import clauses -(\sref{sec:import}), which are collectively called {\em binders}. - -There are two different name spaces, one for types (\sref{sec:types}) -and one for terms (\sref{sec:exprs}). The same name may designate a -type and a term, depending on the context where the name is used. - -A definition or declaration has a {\em scope} in which the entity -defined by a single name can be accessed using a simple name. Scopes -are nested, and a definition or declaration in some inner scope {\em -shadows} a definition in an outer scope that contributes to the same -name space. Furthermore, a definition or declaration shadows bindings -introduced by a preceding import clause, even if the import clause is -in the same block. Import clauses, on the other hand, only shadow -bindings introduced by other import clauses in outer blocks. - -A reference to an unqualified (type- or term-) identifier $x$ is bound -by the unique binder, which -\begin{itemize} -\item defines an entity with name $x$ in the same namespace as the -identifier, and -\item shadows all other binders that define entities with name $x$ in that namespace. -\end{itemize} -It is an error if no such binder exists. If $x$ is bound by an import -clause, then the simple name $x$ is taken to be equivalent to the -qualified name to which $x$ is mapped by the import clause. If $x$ is bound by a definition or declaration, -then $x$ refers to the entity introduced by that -binder. In that case, the type of $x$ is the type of the referenced -entity. - -\example Consider the following nested definitions and imports: - -\begin{verbatim} -object m1 { - object m2 { val x: int = 1; val y: int = 2 } - object m3 { val x: boolean = true; val y: String = "" } - val x: int = 3; - { import m2._; \= // shadows nothing - \> // reference to `x' is ambiguous here - val x: String = "abc"; \> // shadows preceding import and val - \> // `x' refers to latest val definition - { import m3._ \> // shadows only preceding import m2 - \> // reference to `x' is ambiguous here - \> // `y' refers to latest import clause - } - } -} -\end{verbatim} - -A reference to a qualified (type- or term-) identifier $e.x$ refers to -the member of the type $T$ of $e$ which has the name $x$ in the same -namespace as the identifier. It is an error if $T$ is not an object type -(\sref{def:object-type}). The type of $e.x$ is the member type of the -referenced entity in $T$. - -\chapter{\label{sec:types}Types} - -\syntax\begin{verbatim} - Type \=::= \= Type1 `=>' Type - \> |\> `(' [Types] `)' `=>' Type - \> |\> Type1 - Type1 \>::= \> SimpleType {with SimpleType} [Refinement] - SimpleType \>::= \> StableId - \> |\> SimpleType `#' id - \> |\> Path `.' type - \> |\> SimpleType TypeArgs - \> |\> `(' Type ')' - Types \>::= \> Type {`,' Type} -\end{verbatim} - -We distinguish between first-order types and type constructors, which -take type parameters and yield types. A subset of first-order types -called {\em value types} represents sets of (first-class) values. -Value types are either {\em concrete} or {\em abstract}. Every -concrete value type can be represented as a {\em class type}, i.e.\ a -type designator (\sref{sec:type-desig}) that refers to a -class\footnote{We assume that objects and packages also -implicitly define a class (of the same name as the object or package, -but inaccessible to user programs).} (\sref{sec:classes}), -or as a {\em compound type} (\sref{sec:compound-types}) -consisting of class types and possibly -also a refinement (\sref{sec:refinements}) that further constrains the -types of its members. - -A shorthands exists for denoting function types -(\sref{sec:function-types}). Abstract value types are introduced by -type parameters and abstract type bindings (\sref{sec:typedcl}). -Parentheses in types are used for grouping. - -Non-value types capture properties of -identifiers that are not values -(\sref{sec:synthetic-types}). There is no syntax to express these -types directly in Scala. - -\section{Paths}\label{sec:paths} - -\syntax\begin{verbatim} - StableId \=::= \= id - \> |\> Path `.' id - \> |\> [id '.'] super [`[' id `]'] `.' id - Path \>::=\> StableId - \> |\> [id `.'] this -\end{verbatim} - -Paths are not types themselves, but they can be a part of named types -and in that way form a central role in Scala's type system. - -A path is one of the following. -\begin{itemize} -\item -The empty path $\epsilon$ (which cannot be written explicitly in user programs). -\item -\verb@C.this@, where \verb@C@ references a class. -The path \verb@this@ is taken as a shorthand for \verb@C.this@ where -\verb@C@ is the class directly enclosing the reference. -\item -\verb@p.x@ where \verb@p@ is a path and \verb@x@ is a stable member of \verb@p@. -{\em Stable members} are members introduced by value or object -definitions, as well as packages. -\item -\verb@C.super.x@ or \verb@C.super[M].x@ -where \verb@C@ references a class and \verb@x@ references a -stable member of the super class or designated mixin class \verb@M@ of \verb@C@. -The prefix \verb@super@ is taken as a shorthand for \verb@C.super@ where -\verb@C@ is the class directly enclosing the reference. -\end{itemize} -A {\em stable identifier} is a path which ends in an identifier. - -\section{Value Types} - -\subsection{Singleton Types} -\label{sec:singleton-type} - -\syntax\begin{verbatim} - SimpleType ::= Path `.' type -\end{verbatim} - -A singleton type is of the form \verb@p.type@, where \verb@p@ is a -path. The type denotes the set of values consisting of -exactly the value denoted by \verb@p@. - -\subsection{Type Projection} -\label{sec:type-project} - -\syntax\begin{verbatim} -SimpleType ::= SimpleType `#' id -\end{verbatim} - -A type projection \verb@T#x@ references the type member named -\verb@x@ of type \verb@T@. \verb@T@ must be either a singleton type, -or a non-abstract class type, or a Java class type (in either of the -last two cases, it is guaranteed that \verb@T@ has no abstract type -members). - -\subsection{Type Designators} -\label{sec:type-desig} - -\syntax\begin{verbatim} - SimpleType ::= StableId -\end{verbatim} - -A type designator refers to a named value type. It can be simple or -qualified. All such type designators are shorthands for type projections. - -Specifically, the unqualified type name $t$ where $t$ is bound in some -class, object, or package $C$ is taken as a shorthand for -\verb@C.this.type#t@. If $t$ is not bound in a class, object, or -package, then \verb@t@ is taken as a shorthand for -\verb@$\epsilon$.type#t@. - -A qualified type designator has the form \verb@p.t@ where \verb@p@ is -a path (\sref{}) and $t$ is a type name. Such a type designator is -equivalent to the type projection \verb@p.type#x@. - -\example -Some type designators and their expansions are listed below. We assume -a local type parameter \verb@t@, a value \verb@mytable@ -with a type member \verb@Node@ and the standard class \verb@scala.Int@, -\begin{verbatim} - t \=$\epsilon$.type#t - Int \>scala.type#Int - scala.Int \>scala.type#Int - mytable.Node \>mytable.type#Node -\end{verbatim} - -\subsection{Parameterized Types} -\label{sec:param-types} - -\syntax\begin{verbatim} - SimpleType \=::= \= SimpleType TypeArgs - TypeArgs \>::= \> `[' Types `]' -\end{verbatim} - -A parameterized type $T[U_1, ..., U_n]$ consists of a type designator -$T$ and type parameters $U_1 \commadots U_n$ where $n \geq 1$. $T$ -must refer to a type constructor which takes $n$ type parameters $a_1, -..., a_n$ with lower bounds $L_1, ..., L_n$ and upper bounds $U_1, -..., U_n$. - -The parameterized type is well-formed if each actual type parameter -{\em conforms to its bounds}, i.e.\ $L_i\sigma <: T_i <: U_i\sigma$ where $\sigma$ -is the substitution $[a_1 := T_1, ..., a_n := T_n]$. - -\example\label{ex:param-types} -Given the partial type definitions: - -\begin{verbatim} - class TreeMap[a <: Ord[a], b] { ... } - class List[a] { ... } - class I extends Ord[I] { ... } -\end{verbatim} - -the following parameterized types are well formed: - -\begin{verbatim} - HashMap[I, String] - List[I] - List[List[Boolean]] -\end{verbatim} - -\example Given the type definitions of \ref{ex:param-types}, -the following types are ill-formed: - -\begin{verbatim} - HashMap[I] \=// illegal: wrong number of parameters - HashMap[List[I], Boolean] \>// illegal: type parameter not within bound -\end{verbatim} - -\subsection{Compound Types} -\label{sec:compound-types} - -\syntax\begin{verbatim} - Type \=::= \= SimpleType {with SimpleType} [Refinement] - Refinement \>::=\> `{' [RefineStat {`;' RefineStat}] `}' - RefineStat \>::=\> Dcl - \> |\> type TypeDef {`,' TypeDef} - \> |\> -\end{verbatim} - -A compound type \verb@T$_1$ with ... with T$_n$ {R}@ represents -objects with members as given in the component types $T_1 \commadots -T_n$ and the refinement \verb@{R}@. Each component type $T_i$ must be a -class type and the base class sequence generated by types $T_1 -\commadots T_n$ must be well-formed (\sref{sec:basetypes-wf}). A -refinement \verb@{R}@ contains declarations and type -definitions. Each declaration or definition in a refinement must -override a declaration or definition in one of the component types -$T_1 \commadots T_n$. The usual rules for overriding (\sref{}) -apply. If no refinement is given, the empty refinement is implicitly -added, i.e. \verb@T$_1$ with ... with T$_n$@ is a shorthand for -\verb@T$_1$ with ... with T$_n$ {}@. - -\subsection{Function Types} -\label{sec:function-types} - -\syntax\begin{verbatim} - SimpleType \=::= \= Type1 `=>' Type - \> |\> `(' [Types] `)' `=>' Type -\end{verbatim} -The type \verb@(T$_1$, ..., T$_n$) => U@ represents the set of function -values that take arguments of types $T_1 \commadots T_n$ and yield -results of type $U$. In the case of exactly one argument type -\verb@S => T@ is a shorthand for \verb@(S) => T@. Function types -associate to the right, e.g.\ \verb@(S) => (T) => U@ is the same as -\verb@(S) => ((T) => U)@. - -Function types are shorthands for class types that define \verb@apply@ -functions. Specifically, the $n$-ary function type $(T_1 \commadots -T_n)U$ is a shorthand for the class type -\verb@Function$\,n$[$T_1 \commadots T_n$,U]@. Such class -types are defined in the Scala library for \verb@n@ between 0 and 9 as follows. -\begin{verbatim} -package scala; -trait Function$\,n$[-T$_1$, ..., -T$_n$, +R] { - def apply(x$_1$: T$_1$, ..., x$_n$: T$_n$): R; - override def toString() = ""; -} -\end{verbatim} -Hence, function types are covariant in their result type, and -contravariant in their argument types. - -\section{Non-Value 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 -report as the internal types of defined identifiers. - -\subsection{Method Types} -\label{sec:method-types} - -A method type is denoted internally as $(Ts)U$, where $(Ts)$ is a -sequence of types $(T_1 \commadots T_n)$ for some $n \geq 0$ -and $U$ is a (value or method) type. This type represents named -methods that take arguments of types $T_1 \commadots T_n$ -and that return a result of type $U$. - -Method types associate to the right: $(Ts_1)(Ts_2)U$ is treated as -$(Ts_1)((Ts_2)U)$. - -A special case are types of methods without any parameters. They are -written here $[]T$, following the syntax for polymorphic method types -(\sref{sec:poly-types}). Parameterless methods name expressions that -are re-evaluated each time the parameterless method name is -referenced. - -Method types do not exist as types of values. If a method name is used -as a value, its type is implicitly converted to a corresponding -function type (\sref{sec:impl-conv}). - -\example The declarations -\begin{verbatim} -def a: Int -def b (x: Int): Boolean -def c (x: Int) (y: String, z: String): String -\end{verbatim} -produce the typings -\begin{verbatim} -a: [] Int -b: (Int) Boolean -c: (Int) (String, String) String -\end{verbatim} - -\subsection{Polymorphic Method Types} -\label{sec:poly-types} - -A polymorphic method type is denoted internally as \verb@[tps]T@ where -\verb@[tps]@ is a type parameter section -\verb@[a$_1$ <: L$_1$ >: U$_1$, ..., a$_n$ <: L$_n$ >: U$_n$] T@ -for some $n \geq 0$ and \verb@T@ is a -(value or method) type. This type represents named methods that -take type arguments \verb@S$_1$, ..., S$_n$@ which -conform (\sref{sec:param-types}) to the lower bounds -\verb@S$_1$, ..., S$_n$@ and the upper bounds -\verb@U$_1$, ..., U$_n$@ and that yield results of type \verb@T@. - -\example The declarations -\begin{verbatim} -def empty[a]: List[a] -def union[a <: Comparable[a]] (x: Set[a], xs: Set[a]): Set[a] -\end{verbatim} -produce the typings -\begin{verbatim} -empty \=: [a >: All <: Any] List[a] -union \>: [a >: All <: Comparable[a]] (x: Set[a], xs: Set[a]) Set[a] . -\end{verbatim} - -\subsection{Overloaded Types} -\label{sec:overloaded-types} -\newcommand{\overload}{\la\mbox{\sf and}\ra} - - -More than one values or methods are defined in the same scope with the -same name, we model - -An overloaded type consisting of type alternatives $T_1 \commadots -T_n$ $(n \geq 2)$ is denoted internally $T_1 \overload \ldots -\overload T_n$. - -\example The definitions -\begin{verbatim} -def println: unit; -def println(s: string): unit = ...; -def println(x: float): unit = ...; -def println(x: float, width: int): unit = ...; -def println[a](x: a)(tostring: a => String): unit = ... -\end{verbatim} -define a single function \verb@println@ which has an overloaded -type. -\begin{verbatim} -println: \= [] unit $\overload$ - \> (String) unit $\overload$ - \> (float) unit $\overload$ - \> (float, int) unit $\overload$ - \> [a] (a) (a => String) unit -\end{verbatim} - -\example The definitions -\begin{verbatim} -def f(x: T): T = ...; -val f = 0 -\end{verbatim} -define a function \verb@f@ which has type \verb@(x: T)T $\overload$ Int@. - -\section{Base Classes and Member Definitions} -\label{sec:base-classes} - -Types, bounds and base classes of class members depend on the way the -members are referenced. Central here are three notions, namely: -\begin{enumerate} -\item the notion of the base class sequence of a type $T$, -\item the notion of a type $T$ seen as a member of some class $C$ from some - prefix type $S$, -\item the notion of a member binding of some type $T$. -\end{enumerate} -These notions are defined mutually recursively as follows. - -1. The {\em base class sequence} of a type is a sequence of class types, -given as follows. -\begin{itemize} -\item -The base classes of a class type \verb@C@ are the base classes of class -\verb@C@. -\item -The base classes of an aliased type are the base classes of its alias. -\item -The base classes of an abstract type are the base classes of its upper bound. -\item -The base classes of a parameterized type \verb@C[T$_1$, ..., T$_n$]@ are the base classes -of type \verb@C@, where every occurrence of a type parameter $a_i$ -of \verb@C@ has been replaced by the corresponding parameter type $T_i$. -\item -The base classes of a singleton type \verb@p.type@ are the base classes of -the type of \verb@p@. -\item -The base classes of a compound type -\verb@T$_1$ with ... with T$_n$ with {R}@ is the concatenation of the -base classes of all \verb@T$_i$@'s, except that later base classes replace -earlier base classes which are instances of the same class. -\end{itemize} - -2. The notion of a type \verb@T@ -{\em seen as a member of some class \verb@C@ from some prefix type -\verb@S@} makes sense only if the prefix type \verb@S@ -has a type instance of class \verb@C@ as a base class, say -\verb@S'#C[T$_1$, ..., T$_n$]@. Then we define as follows. -\begin{itemize} - \item - If \verb@S = $\epsilon$.type@, then $T$ seen as a member of $C$ from $S$ is $T$ itself. - \item Otherwise, if \verb@T@ is the $i$'th type parameter of some class \verb@D@, then - \begin{itemize} - \item - If \verb@S@ has a base class \verb@D[U$_1$, ..., U$_n$]@, for some type parameters - \verb@[U$_1$, ..., U$_n$]@, then \verb@T@ seen as a member of $C$ from $S$ is $U_i$. - \item - Otherwise, if $C$ is defined in a class $C'$, then - \verb@T@ seen as a member of $C$ from $S$ is the same as $T$ seen as - a member of $C'$ from $S'$. - \item - Otherwise, if $C$ is not defined in another class, then - \verb@T@ seen as a member of $C$ from $S$ is $T$ itself. - \end{itemize} -\item - Otherwise, - if \verb@T@ is the singleton type \verb@D.this.type@ for some class \verb@D@ - then - \begin{itemize} - \item - If \verb@D@ is a subclass of \verb@C@ and - \verb@S@ has a type instance of class $D$ among its base classes. - then \verb@T@ seen as a member of $C$ from $S$ is $S$. - \item - Otherwise, if $C$ is defined in a class $C'$, then - \verb@T@ seen as a member of $C$ from $S$ is the same as $T$ seen as - a member of $C'$ from $S'$. - \item - Otherwise, if $C$ is not defined in another class, then - \verb@T@ seen as a member of $C$ from $S$ is $T$ itself. - \end{itemize} -\item - If $T$ is some other type, then the described mapping is performed - to all its type components. -\end{itemize} - -If \verb@T@ is a possibly parameterized class type, where $T$'s class -is defined in some other class $D$, and \verb@S@ is some prefix type, -then we use ``\verb@T@ seen from \verb@S@'' as a shorthand for -``\verb@T@ seen as a member of $D$ from $S$. - -3. The {\em member bindings} of a type $T$ are all bindings $d$ such that -there exists a type instance of some class $C$ among the base classes of $T$ -and there exists a definition or declaration $d'$ in $C$ -such that $d$ results from $d'$ by replacing every -type $T'$ in $d'$ by $T'$ seen as a member of $C$ from $T$. - -The {\em definition} of a type projection \verb@S#t@ is the member -binding $d$ of the type \verb@t@ in \verb@S@. In that case, we also say -that \verb@S#t@ {\em is defined by} \verb@d@. - -\section{Relations between types} - -We define two relations between types. -\begin{quote}\begin{tabular}{l@{\tab}l@{\tab}l} -\em Type equivalence & $T \equiv U$ & $T$ and $U$ are interchangeable -in all contexts. -\\ -\em Conformance & $T \conforms U$ & Type $T$ conforms to type $U$. -\end{tabular}\end{quote} - -\subsection{Type Equivalence} -\label{sec:type-equiv} - -Equivalence $(\equiv)$ between types is the smallest congruence\footnote{ A -congruence is an equivalence relation which is closed under formation -of contexts} such that the following holds: -\begin{itemize} -\item -If $t$ is defined by a type alias \verb@type t = T@, then $t$ is -equivalent to $T$. -\item -If a path $p$ has a singleton type \verb@q.type@, then -\verb@p.type $\equiv$ q.type@. -\item -If \verb@O@ is defined by an object definition, and \verb@p@ is a path -consisting only of package or object selectors and ending in \verb@O@, then -\verb@O.this.type $\equiv$ p.type@. -\item -Two compound types are equivalent if their component types are -pairwise equivalent and their refinements are equivalent. Two -refinements are equivalent if they bind the same names and the -modifiers, types and bounds of every declared entity are equivalent in -both refinements. -\item -Two method types are equivalent if they have equivalent result -types, both have the same number of parameters, and corresponding -parameters have equivalent types as well as the same \verb@def@ or -\verb@*@ modifiers. Note that the names of parameters do not matter -for method type equivalence. -\item -Two polymorphic types are equivalent if they have the same number of -type parameters, and, after renaming one set of type parameters by -another, the result types as well as lower and upper bounds of -corresponding type parameters are equivalent. -\item -Two overloaded types are equivalent if for every alternative type in -either type there exists an equivalent alternative type in the other. -\end{itemize} - -\subsection{Conformance} -\label{sec:subtyping} - -The conformance relation $(\conforms)$ is the smallest -transitive relation that satisfies the following conditions. -\begin{itemize} -\item Conformance includes equivalence. If $T \equiv U$ then $T \conforms U$. -\item For every value type $T$, \verb@scala.All <: T <: scala.Any@. -\item For every value type \verb@T <: scala.AnyRef@ one has \verb@scala.AllRef <: 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 type projection \verb@T#t@ conforms to \verb@U#t@ if - \verb@T@ conforms to \verb@U@. -\item A parameterized type \verb@T[T$_1$, ..., T$_n$]@ conforms to - \verb@T[U$_1$, ..., U$_n$]@ if - the following three conditions hold for $i = 1 \commadots n$. - \begin{itemize} - \item - If the $i$'th type parameter of $T$ is declared covariant, then $T_i <: U_i$. - \item - If the $i$'th type parameter of $T$ is declared contravariant, then $U_i <: T_i$. - \item - If the $i$'th type parameter of $T$ is declared neither covariant - nor contravariant, then $U_i \equiv T_i$. - \end{itemize} -\item A compound type \verb@T$_1$ with ... with T$_n$ {R}@ conforms to - each of its component types \verb@T$_i$@. -\item If $T \conforms U_i$ for $i = 1 \commadots n$ and for every - binding of a type or value $x$ in $R$ there exists a member binding of - $x$ in $T$ which is more specific, then $T$ conforms to - the compound type \verb@T$_1$ with ... with T$_n$ {R}@. -\item If - $T'_i$ conforms to $T_i$ for $i = 1 \commadots n$ and $U$ conforms to $U'$ - then the method type $(T_1 \commadots T_n) U$ conforms to - $(T'_1 \commadots T'_n) U'$. -\item If, assuming -$L'_1 \conforms a_1 \conforms U'_1 \commadots L'_n \conforms a_n \conforms U'_n$ -one has $L_i \conforms L'_i$ and $U'_i \conforms U_i$ -for $i = 1 \commadots n$, as well as $T \conforms T'$ then the polymorphic type -$[a_1 >: L_1 <: U_1 \commadots a_n >: L_n <: U_n] T$ conforms to the polymorphic type -$[a_1 >: L'_1 <: U'_1 \commadots a_n >: L'_n <: U'_n] T'$. -\item -An overloaded type $T_1 \overload \ldots \overload T_n$ conforms to each of its alternative types $T_i$. -\item -A type $S$ conforms to the overloaded type $T_1 \overload \ldots \overload T_n$ -if $S$ conforms to each alternative type $T_i$. -\end{itemize} - -A declaration or definition in some compound type of class type $C$ -is {\em more specific} than another -declaration of the same name in some compound type or class type $C'$. -\begin{itemize} -\item -A value declaration \verb@val x: T@ or value definition -\verb@val x: T = e@ is more specific than a value declaration -\verb@val x: T'@ if $T <: T'$. -\item -A type alias -$\TYPE;t=T$ is more specific than a type alias $\TYPE;t=T'$ if -$T \equiv T'$. -\item -A type declaration \verb@type t >: L <: U@ is more specific that -a type declaration \verb@type t >: L' <: U'@ if \verb@L' <: L@ and \verb@U <: U'@. -\item -A type or class definition of some type $t$ is more specific than an abstract -type declaration \verb@type t >: L <: U@ if -\verb@L <: t <: U@. -\end{itemize} - -The \verb@<:@ relation forms a partial order between types. The {\em -least upper bound} or the {\em greatest lower bound} of a set of types -is understood to be relative to that order. - -\section{Type Erasure} -\label{sec:erasure} - -A type is called {\em generic} if it contains type arguments or type variables. -{\em Type erasure} is a mapping from (possibly generic) types to -non-generic types. We write $|T|$ for the erasure of type $T$. -The erasure mapping is defined as follows. -\begin{itemize} -\item The erasure of a type variable is the erasure of its upper bound. -\item The erasure of a parameterized type $T[T_1 \commadots T_n]$ is $|T|$. -\item The erasure of a singleton type \verb@p.type@ is the - erasure of the type of \verb@p@. -\item The erasure of a type projection \verb@T#x@ is \verb@|T|#x@. -\item The erasure of a compound type $T_1;\WITH;\ldots;\WITH;T_n\{R\}$ is $|T_1|$. -\item The erasure of every other type is the type itself. -\end{itemize} - -\section{Implicit Conversions} -\label{sec:impl-conv} - -If $S \conforms T$, then values of type $S$ are implicitly {\em -converted} to values type of $T$ in situations where a value of type -$T$ is required. A conversion between two number types in \verb@int@, -\verb@long@, \verb@float@, \verb@double@ creates a value of the target -type representing the same number as the source. When used in an -expression, a value of type \verb@byte@, \verb@char@, \verb@short@ is -always implicitly converted to a value of type \verb@int@. - -The following implicit conversions are applied to expressions of -method type that are used as values, rather than being applied to some -arguments. -\begin{itemize} -\item -A parameterless method $m$ of type $[] T$ -is converted to type $T$ by evaluating the expression to which $m$ is bound. -\item -An expression $e$ of polymorphic type -\verb@[a$_1$ >: L$_1$ <: U$_1$, ..., a$_n$ >: L$_n$ <: U$_n$]T@ -which does not appear as the function part of -a type application is converted to type \verb@T@ -by determining with local type inference -(\sref{sec:local-type-inf}) instance types \verb@T$_1$, ..., T$_n$@ -for the type variables \verb@a$_1$, ..., a$_n$@ and -implicitly embedding \verb@e@ in the type application -\verb@e[U$_1$, ..., U$_n$]@ (\sref{sec:type-app}). -\item -An expression \verb@e@ of monomorphic method type -$(Ts_1) \ldots (Ts_n) U$ of arity $n > 0$ -which does not appear as the function part of an application is -converted to a function type by implicitly embedding $e$ in -the following term, where $x$ is a fresh variable and each $ps_i$ is a -parameter section consisting of parameters with fresh names of types $Ts_i$. - -\begin{verbatim} -(val $x$ = $e$ ; $(ps_1) \ldots \Arrow \ldots \Arrow (ps_n) \Arrow x;(ps_1);\ldots;(ps_n)$) -\end{verbatim} -This conversion is not applicable to functions with call-by-name -parameters (\sref{sec:parameters}) of type $[]T$, because its result -would violate the well-formedness rules for anonymous functions -(\sref{sec:closures}). Hence, methods with call-by-name -parameters always need to be applied to arguments immediately. -\end{itemize} - -\chapter{Basic Declarations and Definitions} -\label{sec:defs} - -\syntax\begin{verbatim} - Dcl \=::=\= val ValDcl {`,' ValDcl} - \> |\> var VarDcl {`,' VarDcl} - \> |\> def FunDcl {`,' FunDcl} - \> |\> type TypeDcl {`,' TypeDcl} - Def \>::=\> val PatDef {`,' PatDef} - \> |\> var VarDef {`,' VarDef} - \> |\> def FunDef {`,' FunDef} - \> |\> type TypeDef {`,' TypeDef} - \> |\> ClsDef -\end{verbatim} - -A {\em declaration} introduces names and assigns them types. It can -appear as one of the statements of a class definition -(\sref{sec:templates}) or as part of a refinement in a compound -type (\sref{sec:refinements}). - -A {\em definition} introduces names that denote terms or types. It can -form part of an object or class definition or it can be local to a -block. Both declarations and definitions produce {\em bindings} that -associate type names with type definitions or bounds, and that -associate term names with types. - -The scope of a name introduced by a declaration or definition is the -whole statement sequence containing the binding. However, there is a -restriction on forward references: In a statement sequence $s_1 \ldots -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. - -\comment{ -Every basic definition may introduce several defined names, separated -by commas. These are expanded according to the following scheme: -\bda{lcl} -\VAL;x, y: T = e && \VAL; x: T = e \\ - && \VAL; y: T = x \\[0.5em] - -\LET;x, y: T = e && \LET; x: T = e \\ - && \VAL; y: T = x \\[0.5em] - -\DEF;x, y (ps): T = e &\tab\mbox{expands to}\tab& \DEF; x(ps): T = e \\ - && \DEF; y(ps): T = x(ps)\\[0.5em] - -\VAR;x, y: T := e && \VAR;x: T := e\\ - && \VAR;y: T := x\\[0.5em] - -\TYPE;t,u = T && \TYPE; t = T\\ - && \TYPE; u = t\\[0.5em] -\eda -} - -All definitions have a ``repeated form'' where the initial -definition keyword is followed by several constituent definitions -which are separated by commas. A repeated definition is -always interpreted as a sequence formed from the -constituent definitions. E.g.\ the function definition -\verb@def f(x) = x, g(y) = y@ expands to -\verb@def f(x) = x; def g(y) = y@ and -the type definition -\verb@type T$_1$, T$_2$ <: B$_2$@ expands to -\verb@type T$_1$; type T$_2$ <: B$_2$@. - -\section{Value Declarations and Definitions} -\label{sec:valdef} - -\syntax\begin{verbatim} - Dcl \=::= \= val ValDcl {`,' ValDcl} - ValDcl \>::= \> id `:' Type - Def \>::= \> val PatDef {`,' PatDef} - PatDef \>::= \> Pattern `=' Expr -\end{verbatim} - -A value declaration \verb@val x: T@ introduces \verb@x@ as a name of a value of -type \verb@T@. - -A value definition \verb@val x: T = e@ defines $x$ as a name of the -value that results from the evaluation of $e$. The type $T$ may be -omitted, in which case the type of expression $e$ is assumed. -If a type $T$ is given, then $e$ is expected to conform to it. - -Evaluation of the value definition implies evaluation of its -right-hand side $e$. The effect of the value definition is to bind -$x$ to the value of $e$ converted to type $T$. - -Value definitions can alternatively have a pattern -(\sref{sec:patterns}) as left-hand side. If $p$ is some pattern other -than a simple name or a name followed by a colon and a type, then the -value definition \verb@val p = e@ is expanded as follows: - -1. If the pattern $p$ has bound variables $x_1 \commadots x_n$, where $n > 1$: -\begin{verbatim} -val $\Dollar$x = e.match {case p => scala.Tuple$\,n$(x$_1$, ..., x$_n$)} -val x$_1$ = $\Dollar$x._1 -... -val x$_n$ = $\Dollar$x._n . -\end{verbatim} -Here, \verb@$\Dollar$x@ is a fresh name. The class -\verb@Tuple$\,n$@ is defined for $n = 2,...,9$ in package -\verb@scala@. - -2. If $p$ has a unique bound variable $x$: -\begin{verbatim} -val x = e.match { case p => x } -\end{verbatim} - -3. If $p$ has no bound variables: -\begin{verbatim} -e.match { case p => ()} -\end{verbatim} - -\example -The following are examples of value definitions -\begin{verbatim} -val pi = 3.1415; -val pi: double = 3.1415; \=// equivalent to first definition -val Some(x) = f(); \>// a pattern definition -val x :: xs = mylist; \>// an infix pattern definition -\end{verbatim} - -The last two definitions have the following expansions. -\begin{verbatim} -val x = f().match { case Some(x) => x } - -val x$\Dollar$ = mylist.match { case x :: xs => scala.Tuple2(x, xs) } -val x = x$\Dollar$._1; -val xs = x$\Dollar$._2; - -\end{verbatim} - -\section{Variable Declarations and Definitions} -\label{sec:vardef} - -\syntax\begin{verbatim} - Dcl \=::= \= var VarDcl {`,' VarDcl} - Def \>::= \> var ValDef {`,' ValDef} - VarDcl \>::=\> id `:' Type - VarDef \>::=\> id [`:' Type] `=' Expr - \> |\> id `:' Type `=' `_' -\end{verbatim} - -A variable declaration \verb@var x: T@ is equivalent to declarations -of a {\em getter function} \verb@x@ and a {\em setter function} -\verb@x_=@, defined as follows: - -\begin{verbatim} - def x: T; - def x_= (y: T): unit -\end{verbatim} - -An implementation of a class containing variable declarations -may define these variables using variable definitions, or it may -define setter and getter functions directly. - -A variable definition \verb@var x: T = e@ introduces a mutable -variable with type \verb@T@ and initial value as given by the -expression \verb@e@. The type $T$ can be omitted, -in which case the type of $e$ is assumed. If $T$ is given, then \verb@e@ -is expected to conform to it. - -A variable definition \verb@var x: T = _@ introduces a mutable -variable with type \verb@T@ and a default initial value. -The default value depends on the type \verb@T@ as follows: -\begin{quote}\begin{tabular}{ll} -\verb@0@ & if $T$ is \verb@int@ or one of its subrange types, \\ -\verb@0L@ & if $T$ is \verb@long@,\\ -\verb@0.0f@ & if $T$ is \verb@float@,\\ -\verb@0.0d@ & if $T$ is \verb@double@,\\ -\verb@false@ & if $T$ is \verb@boolean@,\\ -\verb@()@ & if $T$ is \verb@unit@, \\ -\verb@null@ & for all other types $T$. -\end{tabular}\end{quote} - -When they occur as members of a template, both forms of variable -definition also introduce a getter function \verb@x@ which returns the -value currently assigned to the variable, as well as a setter function -\verb@x_=@ which changes the value currently assigned to the variable. -The functions have the same signatures as for a variable declaration. -The getter and setter functions, are then members of the template -instead of the variable accessed by them. - -\example The following example shows how {\em properties} can be -simulated in Scala. It defines a class \verb@TimeOfDayVar@ of time -values with updatable integer fields representing hours, minutes, and -seconds. Its implementation contains tests that allow only legal -values to be assigned to these fields. The user code, on the other -hand, accesses these fields just like normal variables. - -\begin{verbatim} -class TimeOfDayVar { - private var h: int = 0, m: int = 0, s: int = 0; - def hours \== h; - def hours_= (h: int) \>= \=if (0 <= h && h < 24) this.h = h - \> \>else new DateError().throw; - def minutes \>= m - def minutes_= (m: int) \>= if (0 <= m && m < 60) this.m = m - \> \>else new DateError().throw; - def seconds \>= s - def seconds_= (s: int) \>= if (0 <= s && s < 60) this.s = s - \> \>else new DateError().throw; -} -val t = new TimeOfDayVar; -d.hours = 8; d.minutes = 30; d.seconds = 0; -d.hours = 25; \=// throws a DateError exception -\end{verbatim} - -\section{Type Declarations and Type Aliases} -\label{sec:typedcl} -\label{sec:typealias} - -\syntax\begin{verbatim} - Dcl \=::= \= type TypeDcl {`,' TypeDcl} - TypeDcl \>::= \> id [>: Type] [<: Type] - Def \>::= \> type TypeDef {`,' TypeDef} - TypeDef \>::= \> id [TypeParamClause] `=' Type -\end{verbatim} - -A {\em type declaration} \verb@type t >: L <: U@ declares \verb@t@ to -be an abstract type with lower bound type \verb@L@ and upper bound -type \verb@U@. If such a declaration appears as a member declaration -of a type, implementations of the type may implement \verb@t@ with any -type \verb@T@ for which \verb@L <: T <: U@. Either or both bounds may -be omitted. If the lower bound \verb@L@ is missing, the bottom type -\verb@scala.All@ is assumed. If the upper bound \verb@U@ is missing, -the top type \verb@scala.Any@ is assumed. - -A {\em type alias} \verb@type t = T@ defines \verb@t@ to be an alias -name for the type \verb@T@. The left hand side of a type alias may -have a type parameter clause, e.g. \verb@type t[tps] = T@. The scope -of a type parameter extends over the right hand side \verb@T@ and the -type parameter clause \verb@tps@ itself. - -The scope rules for definitions (\sref{sec:defs}) and type parameters -(\sref{sec:funsigs}) make it possible that a type name appears in its -own bound or in its right-hand side. However, it is a static error if -a type alias refers recursively to the defined type constructor itself. -That is, the type \verb@T@ in a type alias \verb@type t[tps] = T@ may not refer -directly or indirectly to the name \verb@t@. It is also an error if -an abstract type is directly or indirectly its own bound. - -\example The following are legal type declarations and definitions: -\begin{verbatim} -type IntList = List[Integer]; -type T <: Comparable[T]; -type Two[a] = Tuple2[a, a]; -\end{verbatim} - -The following are illegal: -\begin{verbatim} -type Abs = Comparable[Abs]; \=// recursive type alias - -type S <: T; \>// S, T are bounded by themselves. -type T <: S; - -type T <: Object with T; \>// T is abstract, may not be part of - \>// compound type - -type T >: Comparable[T.That]; \>// Cannot select from T. - \>// T is a type, not a value -\end{verbatim} - -If a type alias \verb@type t[tps] = S@ refers to a class type -\verb@S@, the name \verb@t@ can also be used as a constructor for -objects of type \verb@S@. - -\example The \verb@Predef@ module contains a definition which establishes \verb@Pair@ -as an alias of the parameterized class \verb@Tuple2@: -\begin{verbatim} -type Pair[+a, +b] = Tuple2[a, b]; -\end{verbatim} -As a consequence, for any two types \verb@S@ and \verb@T@, the type -\verb@Pair[S, T]@ is equivalent to the type \verb@Tuple2[S, T]@. -\verb@Pair@ can also be used as a constructor instead of \verb@Tuple2@, as in -\begin{verbatim} -new Pair[Int, Int](1, 2) . -\end{verbatim} - -\section{Type Parameters} - -\syntax\begin{verbatim} - TypeParamClause \=::=\= `[' TypeParam {`,' TypeParam} `]' - TypeParam \>::=\> [`+' | `-'] TypeDcl -\end{verbatim} - -\newcommand{\plusminus}{\oplus} - -Type parameters appear in type definitions, class definitions, and -function definitions. The most general form of a type parameter is -\verb@$\plusminus$ t >: L <: U@. Here, \verb@L@, and \verb@U@ are lower -and upper bounds that constrain possible type arguments for the -parameter. $\plusminus$ is a {\em variance}, i.e.\ an optional prefix -of either \verb@+@, or \verb@-@. - -The names of all type parameters in a type parameter clause must be -pairwise different. The scope of a type parameter includes in each -case the whole type parameter clause. Therefore it is possible that a -type parameter appears as part of its own bounds or the bounds of -other type parameters in the same clause. However, a type parameter -may not be bounded directly or indirectly by itself. - -\example Here are some well-formed type parameter clauses: -\begin{verbatim} -[s, t] -[ex <: Throwable] -[a <: Ord[b], b <: a] -[a, b, c >: a <: b] -\end{verbatim} -The following type parameter clauses since some type parameter is bounded by itself. -\begin{verbatim} -[a >: a] -[a <: b, b <: c, c <: a] -\end{verbatim} - -Variance annotations indicate how type instances with the given type -parameters vary with respect to subtyping (\sref{sec:subtyping}). A -`\verb@+@' variance indicates a covariant dependency, a `\verb@-@' -variance indicates a contravariant dependency, and a missing variance -indication indicates an invariant dependency. - -A variance annotation constrains the way the annotated type variable -may appear in the type or class which binds the type parameter. In a -type definition \verb@type t[tps] = S@, type parameters labeled -`\verb@+@' must only appear in covariant position in \verb@S@ whereas -type parameters labeled `\verb@-@' must only appear in contravariant -position. Analogously, for a class definition -\verb@class c[tps](ps): s extends t@, type parameters labeled -`\verb@+@' must only appear in covariant position in the self type -\verb@s@ and the type of the template \verb@t@, whereas type -parameters labeled `\verb@-@' must only appear in contravariant -position. - -The variance position of a type parameter of a type is defined as -follows. Let the opposite of covariance be contravariance, and the -opposite of invariance be itself. The top-level of a type is always -in covariant position. The variance position changes at the following -constructs. -\begin{itemize} -\item -The variance position of method parameter is the opposite of the -variance position of the enclosing parameter clause. -\item -The variance position of a type parameter is the opposite of the -variance position of the enclosing type parameter clause. -\item -The variance position of the lower bound of a type declaration or type parameter -is the opposite of the variance position of the type declaration or parameter. -\item -The right hand side \verb@S@ of a type alias \verb@type t[tps] = S@ -is always in invariant position. -\item -The type of a mutable variable is always in invariant position. -\item -The prefix \verb@S@ of a type selection \verb@S#T@ is always in invariant position. -\item -For a type argument \verb@T@ of a type \verb@S[... T ... ]@: If the -corresponding type parameter is invariant, then \verb@T@ is in -invariant position. If the corresponding type parameter is -contravariant, the variance position of \verb@T@ is the opposite of -the variance position of the enclosing type \verb@S[... T ... ]@. -\end{itemize} - -\example The following variance annotation is legal. -\begin{verbatim} -class P[a, b] { - val fst: a, snd: b -}\end{verbatim} -With this variance annotation, elements -of type \verb@P@ subtype covariantly with respect to their arguments. -For instance, \verb@P[IOExeption, String] <: P[Throwable, Object]@. - -If we make the elements of \verb@P@ mutable, -the variance annotation becomes illegal. -\begin{verbatim} -class Q[+a, +b] { - var fst: a, snd: b // **** error: illegal variance: `a', `b' occur in invariant position. -} -\end{verbatim} - -\example The following variance annotation is illegal, since \verb@a@ appears -in contravariant position in the parameter of \verb@append@: - -\begin{verbatim} -trait Vector[+a] { - def append(x: Vector[a]): Vector[a]; // **** error: illegal variance: `a' occurs in contravariant position. -} -\end{verbatim} -The problem can be avoided by generalizing the type of \verb@append@ -by means of a lower bound: - -\begin{verbatim} -trait Vector[+a] { - def append[b >: a](x: Vector[b]): Vector[b]; -} -\end{verbatim} - -\example Here is a case where a contravariant type parameter is useful. - -\begin{verbatim} -trait OutputChannel[-a] { - def write(x: a): unit -} -\end{verbatim} -With that annotation, we have -\verb@OutputChannel[Object] <: OutputChannel[String]@. That is, a -channel on which one can write any object can substitute for a channel -on which one can write only strings. - -\section{Function Declarations and Definitions} -\label{sec:defdef} -\label{sec:funsigs} - -\syntax\begin{verbatim} -Dcl \=::= \= def FunDcl {`,' FunDcl} -FunDcl \>::= \> id [FunTypeParamClause] {ParamClause} `:' Type -Def \>::= \> def FunDef {`,' FunDef} -FunDef \>::= \> id [FunTypeParamClause] {ParamClause} [`:' Type] - \> \> `=' Expr -FunTypeParamClause \>::=\> `[' TypeDcl {`,' TypeDcl} `]' -ParamClause \>::=\> `(' [Param {`,' Param}] `)' -Param \>::= \> [def] id `:' Type [*] -\end{verbatim} - -A function declaration has the form \verb@def f psig: T@, where -\verb@f@ is the function's name, \verb@psig@ is its parameter -signature and \verb@T@ is its result type. A function definition -\verb@f psig:T = e@ also includes a {\em function body} \verb@e@, -i.e.\ an expression which defines the function's result. A parameter -signature consists of an optional type parameter clause \verb@[tps]@, -followed by zero or more value parameter clauses -\verb@(ps$_1$) ... (ps$_n$)@. Such a declaration or definition -introduces a value with a (possibly polymorphic) method type whose -parameter types and result type are as given. - -A type parameter clause \verb@tps@ consists of one or more type -declarations (\sref{sec:typedcl}), which introduce type parameters, -possibly with bounds. The scope of a type parameter includes -the whole signature, including any of the type parameter bounds as -well as the function body, if it is present. - -A value parameter clause \verb@ps@ consists of zero or more formal -parameter bindings such as \verb@x: T@, which bind value -parameters and associate them with their types. The scope of a formal -value parameter name \verb@x@ is the function body, if one is -given. Both type parameter names and value parameter names must be -pairwise distinct. - -Value parameters may be prefixed by \verb@def@, e.g.\ -\verb@def x:T@. The type of such a parameter is then the -parameterless method type \verb@[]T@. This indicates that the -corresponding argument is not evaluated at the point of function -application, but instead is evaluated at each use within the -function. That is, the argument is evaluated using {\em call-by-name}. - -\example The declaration -\begin{verbatim} -def whileLoop (def cond: Boolean) (def stat: Unit): Unit -\end{verbatim} -produces the typing -\begin{verbatim} -whileLoop: (cond: [] Boolean) (stat: [] Unit) Unit -\end{verbatim} -which indicates that both parameters of \verb@while@ are evaluated using -call-by-name. - -The type of the function body must conform to the function's declared -result type, if one is given. If the function definition is not -recursive, the result type may be omitted, in which case it is -determined from the type of the function body. - -\section{Overloaded Definitions} -\label{sec:overloaded-defs} -\todo{change} - -An overloaded definition is a set of \verb@n > 1@ value or function -definitions in the same statement sequence that define the same name, -binding it to types \verb@T_1, ..., T_n@, respectively. The -individual definitions are called {\em alternatives}. Alternatives -always need to specify the type of the defined entity completely. All -alternatives must have the same modifiers. It is an error if the types -of two alternatives \verb@T$_i$@ and \verb@T$_j$@ have the same -erasure (\sref{sec:erasure}). An overloaded definition defines a -single entity, of type \verb@T_1 $\overload$ ... $\overload$ T_n@ -(\sref{sec:overloaded-types}). - -\todo{Say something about bridge methods.} -%This must be a well-formed -%overloaded type - -\section{Import Clauses} -\label{sec:import} - -\syntax\begin{verbatim} - Import \=::=\= import ImportExpr {`,' ImportExpr} - ImportExpr \>::=\> StableId `.' (id | `_' | ImportSelectors) - ImportSelectors \>::=\> `{' {ImportSelector `,'} (ImportSelector | `_') `}' - ImportSelector \>::=\> id [`=>' id | `=>' `_'] -\end{verbatim} - -An import clause has the form \verb@import p.I@ where \verb@p@ is a stable -identifier (\sref{sec:paths}) and \verb@I@ is an import expression. -The import expression determines a set of names of members of \verb@p@ -which are made available without qualification. The most general form -of an import expression is a list of {\em import selectors} -\begin{verbatim} -{ x$_1$ => y$_1$, ..., x$_n$ => y$_n$, _ } -\end{verbatim} -for $n \geq 0$, where the final wildcard `\verb@_@' may be absent. It -makes available each member \verb@p.x$_i$@ under the unqualified name -\verb@y$_i$@. I.e.\ every import selector \verb@x$_i$ => y$_i$@ renames -\verb@p.x$_i$@ to -\verb@y$_i$@. If a final wildcard is present, all members \verb@z@ of -\verb@p@ other than \verb@x$_1$, ..., x$_n$@ are also made available -under their own unqualified names. - -Import selectors work in the same way for type and term members. For -instance, an import clause \verb@import p.{x => y}@ renames the term -name \verb@p.x@ to the term name \verb@y@ and the type name \verb@p.x@ -to the type name \verb@y@. At least one of these two names must -reference a member of \verb@p@. - -If the target in an import selector is a wildcard, the import selector -hides access to the source member. For instance, the import selector -\verb@x => _@ ``renames'' \verb@x@ to the wildcard symbol (which is -unaccessible as a name in user programs), and thereby effectively -prevents unqualified access to \verb@x@. This is useful if there is a -final wildcard in the same import selector list, which imports all -members not mentioned in previous import selectors. - -Several shorthands exist. An import selector may be just a simple name -\verb@x@. In this case, \verb@x@ is imported without renaming, so the -import selector is equivalent to \verb@x => x@. Furthermore, it is -possible to replace the whole import selector list by a single -identifier or wildcard. The import clause \verb@import p.x@ is -equivalent to \verb@import p.{x}@, i.e.\ it makes available without -qualification the member \verb@x@ of \verb@p@. The import clause -\verb@import p._@ is equivalent to -\verb@import p.{_}@, -i.e.\ it makes available without qualification all members of \verb@p@ -(this is analogous to \verb@import p.*@ in Java). - -An import clause with multiple import expressions -\verb@import p$_1$.I$_1$, ..., p$_n$.I$_n$@ is interpreted as a -sequence of import clauses -\verb@import p$_1$.I$_1$; ..., import p$_n$.I$_n$@. - -\example Consider the object definition: -\begin{verbatim} -object M { - def z = 0, one = 1; - def add(x: Int, y: Int): Int = x + y -} -\end{verbatim} -Then the block -\begin{verbatim} -{ import M.{one, z => zero, _}; add(zero, one) } -\end{verbatim} -is equivalent to the block -\begin{verbatim} -{ M.add(M.z, M.one) } . -\end{verbatim} - -\chapter{Classes and Objects} -\label{sec:globaldefs} - -\syntax\begin{verbatim} - ClsDef \=::=\= ([case] class | trait) ClassDef {`,' ClassDef} - \> |\> [case] object ObjectDef {`,' ObjectDef} -\end{verbatim} - -Classes (\sref{sec:classes}) and objects -(\sref{sec:modules}) are both defined in terms of {\em templates}. - -\section{Templates} -\label{sec:templates} - -\syntax\begin{verbatim} - Template \=::=\= Constr {`with' Constr} [TemplateBody] - TemplateBody \>::=\> `{' [TemplateStat {`;' TemplateStat}] `}' -\end{verbatim} - -A template defines the type signature, behavior and initial state of a -class of objects or of a single object. Templates form part of -instance creation expressions, class definitions, and object -definitions. A template -\verb@sc with mc$_1$ with ... with mc$_n$ {stats}@ consists of a -constructor invocation \verb@sc@ which defines the template's {\em -superclass}, constructor invocations \verb@mc$_1$, ..., mc$_n$@ -$(n \geq 0)$, which define the template's {\em mixin classes}, and a -statement sequence \verb@stats@ which contains additional member -definitions for the template. Superclass and mixin classes together -are called the {\em parent classes} of a template. The superclass of -a template must be a subtype of the superclass of each mixin class. -The {\em least proper supertype} of a template is the class type or -compound type (\sref{sec:compound-types}) consisting of the its parent classes. - -Member definitions define new members or overwrite members in the -parent classes. If the template forms part of a class definition, -the statement part \verb@stats@ may also contain declarations of abstract members. -%The type of each non-private definition or declaration of a -%template must be equivalent to a type which does not refer to any -%private members of that template. - -\todo{Make all references to Java generic} - -\paragraph{Inheriting from Java Types} A template may have a Java class as -its superclass and Java interfaces as its mixin classes. On the other -hand, it is not permitted to have a Java class as a mixin class, or a -Java interface as a superclass. - -\subsection{Constructor Invocations} -\label{sec:constr-invoke} -\syntax\begin{verbatim} - Constr \=::= \= StableId [TypeArgs] [`(' [Exprs] `)'] -\end{verbatim} - -Constructor invocations define the type, members, and initial state of -objects created by an instance creation expression, or of parts of an -object's definition which are inherited by a class or object -definition. A constructor invocation is a function application -\verb@x.c(args)@, where \verb@x@ is a stable identifier -(\sref{sec:stable-ids}), \verb@c@ is a type name which either -designates a class or defines an alias type for one, and \verb@(args)@ -is an argument list, which matches one of the constructors of that -class. The prefix `\verb@x.@' can be omitted. -%The class \verb@c@ must conform to \verb@scala.AnyRef@, -%i.e.\ it may not be a value type. -The argument list \verb@(args)@ can also be omitted, in which case an -empty argument list \verb@()@ is implicitly added. - -\subsection{Base Classes} -\label{sec:base-classes} - -For every template, class type and constructor invocation we define two -sequences of class types: the {\em base classes} and {\em mixin base -classes}. Their definitions are as follows. - -The {\em mixin base classes} of a template -\verb@sc with mc$_1$ with ... with mc$_n$ {stats}@ are obtained by -concatenating, for each $i = 1 \commadots n$, the mixin base classes -of the mixin \verb@mc_i@. The mixin base classes of a class type \verb@C@ are -the mixin base classes of the template represented by \verb@C@, followed by -\verb@C@ itself. The mixin base classes of a constructor invocation of type -\verb@T@ are the mixin base classes of class \verb@T@. - -The {\em base classes} of a template consist of the base classes of -its superclass, followed by the template's mixin base classes. The -base classes of class \verb@scala.Any@ consist of just the -class itself. The base classes of some other class type \verb@C@ are the -base classes of the template represented by \verb@C@, followed by \verb@C@ -itself. The base classes of a constructor invocation of type \verb@T@ -are the base classes of \verb@T@. - -The notions of mixin base classes and base classes are extended from -classes to arbitrary types following the definitions of -\sref{sec:base-classes}. - -If two types in the base class sequence of a template refer to the -same class definition, then that definition must define a trait -(\sref{sec:traits}), and the type that comes later in the sequence must -conform to the type that comes first. -(\sref{sec:case-classes}). - -\subsection{Evaluation} - -The evaluation of a template or constructor invocation depends on -whether the template defines an object or is a superclass of a -constructed object, or whether it is used as a mixin for a defined -object. In the second case, the evaluation of a template used as a -mixin depends on an {\em actual superclass}, which is known at the -point where the template is used in a definition of an object, but not -at the point where it is defined. The actual superclass is used in the -determination of the meaning of \verb@super@ (\sref{sec:this-super}). - -We therefore define two notions of template evaluation: (Plain) -evaluation (as a defining template or superclass) and mixin evaluation -with a given superclass \verb@sc@. These notions are defined for templates -and constructor invocations as follows. - -A {\em mixin evaluation with superclass \verb@sc@} of a template -\verb@sc' with mc$_1$ with mc$_n$ with {stats}@ consists of mixin -evaluations with superclass \verb@sc@ of the mixin constructor invocations -\verb@mc$_1$, ..., mc$_n$@ in the order they are given, followed by an -evaluation of the statement sequence \verb@stats@. Within \verb@stats@ the -actual superclass refers to \verb@sc@. A mixin evaluation with superclass -\verb@sc@ of a class constructor invocation \verb@ci@ consists of an evaluation -of the constructor function and its arguments in the order they are -given, followed by a mixin evaluation with superclass \verb@sc@ of the -template represented by the constructor invocation. - -An {\em evaluation} of a template -\verb@sc with mc$_1$ with mc$_n$ with (stats)@ consists of an evaluation of -the superclass constructor invocation \verb@sc@, -followed by a mixin evaluation with superclass \verb@sc@ of the template. An -evaluation of a class constructor invocation \verb@ci@ consists of an -evaluation of the constructor function and its arguments in -the order they are given, followed by an evaluation of the template -represented by the constructor invocation. - -\subsection{Template Members} - -\label{sec:members} - -The object resulting from evaluation of a template has directly bound -members and inherited members. Members can be abstract or concrete. -These are defined as follows. -\begin{enumerate} -\item -A {\em directly bound} member is an entity introduced by a member -definition or declaration in the template's statement sequence. The -member is called {\em abstract} if it is introduced by a declaration, -{\em concrete} otherwise. -\item -A {\em concrete inherited} member is a non-private, concrete member of -one of the template's base classes \verb@B@, except if a member with the -same \ifqualified{qualified} name is already directly bound in the template, or is -directly bound in a base class of the template which is a subclass of -\verb@B@, or is a directly bound, non-private, concrete member of a base -class which succeeds \verb@B@ in the base class sequence of the template. -\item -An {\em abstract inherited} member is a non-private, abstract member -of one of the template's base classes \verb@B@, except if a member with the -same \ifqualified{qualified} name is already directly bound in the template, or is a -concrete inherited member, or is a directly bound, non-private member -of a base class which succeeds \verb@b@ in the base class sequence of the -template. -\end{enumerate} - -If two mixin classes of a template each have a concrete member -with the same name, then the template itself must also declare or -define a member with the same name. - -\comment{ -The type of a member \verb@m@ is determined as follows: If \verb@m@ is defined -in \verb@stats@, then its type is the type as given in the member's -declaration or definition. Otherwise, if \verb@m@ is inherited from the -base class \verb@B[T1, .... T_n]@, \verb@B@'s class declaration has formal -parameters \verb@[a_1, ..., a_n]@, and \verb@M@'s type in \verb@B@ is \verb@U@, then -\verb@M@'s type in \verb@C@ is \verb@U[a_1 := T_1, ..., a_n := T_n]@. - -\ifqualified{ -Members of templates have internally qualified names $Q\qex x$ where -$x$ is a simple name and $Q$ is either the empty name $\epsilon$, or -is a qualified name referencing the module or class that first -introduces the member. A basic declaration or definition of $x$ in a -module or class $M$ introduces a member with the following qualified -name: -\begin{enumerate} -\item -If the binding is labeled with an \verb@override $Q$@\nyi{Override - with qualifier} modifier, -where $Q$ is a fully qualified name of a base class of $M$, then the -qualified name is the qualified expansion (\sref{sec:names}) of $x$ in -$Q$. -\item -If the binding is labeled with an \verb@override@ modifier without a -base class name, then the qualified name is the qualified expansion -of $x$ in $M$'s least proper supertype (\sref{sec:templates}). -\item -An implicit \verb@override@ modifier is added and case (2) also -applies if $M$'s least proper supertype contains an abstract member -with simple name $x$. -\item -If no \verb@override@ modifier is given or implied, then if $M$ is -labeled \verb@qualified@, the qualified name is $M\qex x$. If $M$ is -not labeled \verb@qualified@, the qualified name is $\epsilon\qex x$. -\end{enumerate} -} -} - -\example Consider the class definitions - -\begin{verbatim} -class A { def f: Int = 1 ; def g: Int = 2 ; def h: Int = 3 } -abstract class B { def f: Int = 4 ; def g: Int } -abstract class C extends A with B { def h: Int } -\end{verbatim} - -Then class \verb@C@ has a directly bound abstract member \verb@h@. It -inherits member \verb@f@ from class \verb@B@ and member \verb@g@ from -class \verb@A@. - -\ifqualified{ -\example\label{ex:compound-b} -Consider the definitions: -\begin{verbatim} -qualified class Root extends Any with { def r1: Root, r2: Int } -qualified class A extends Root with { def r1: A, a: String } -qualified class B extends A with { def r1: B, b: Double } -\end{verbatim} -Then \verb@A with B@ has members -\verb@Root::r1@ of type \verb@B@, \verb@Root::r2@ of type \verb@Int@, -\verb@A::a:@ of type \verb@String@, and \verb@B::b@ of type \verb@Double@, -in addition to the members inherited from class \verb@Any@. -} - -\subsection{Overriding} -\label{sec:overriding} - -A template member \verb@M@ that has the same \ifqualified{qualified} -name as a non-private member \verb@M'@ of a base class (and that -belongs to the same namespace) is said to {\em override} that member. -In this case the binding of the overriding member \verb@M@ must be -more specific (\sref{sec:subtyping}) than the binding of the -overridden member \verb@M'@. Furthermore, the overridden definition -may not be a class definition. Method definitions may only override -other method definitions (or the methods implicitly defined by a -variable definition). They may not override value let definitions. -Finally, the following restrictions on modifiers apply to \verb@M@ and -\verb@M'@: -\begin{itemize} -\item -\verb@M'@ must not be labeled \verb@final@. -\item -\verb@M@ must not be labeled \verb@private@. -\item -If \verb@M@ is labeled \verb@protected@, then \verb@M'@ must also be -labeled \verb@protected@. -\item -If \verb@M'@ is not an abstract member, then -\verb@M@ must be labeled \verb@override@. -\end{itemize} - -\example\label{ex:compound-a} -Consider the definitions: -\begin{verbatim} -trait Root with { type T <: Root } -trait A extends Root with { type T <: A } -trait B extends Root with { type T <: B } -trait C extends A with B; -\end{verbatim} -Then the trait definition \verb@C@ is not well-formed because the -binding of \verb@T@ in \verb@C@ is -\verb@type T extends B@, -which fails to be more specific than the binding of same name in type -\verb@A@. The problem can be solved by adding an overriding -definition of type \verb@T@ in class \verb@C@: -\begin{verbatim} -class C extends A with B { type T <: C } -\end{verbatim} - -\subsection{Modifiers} -\label{sec:modifiers} - -\syntax\begin{verbatim} - Modifier \=::=\= LocalModifier - \> |\> private - \> |\> protected - \> |\> override - LocalModifier \>::=\> abstract - \> |\> final - \> |\> sealed -\end{verbatim} - -Member definitions may be preceded by modifiers which affect the -\ifqualified{qualified names, }accessibility and usage of the -identifiers bound by them. If several modifiers are given, their -order does not matter, but the same modifier may not occur repeatedly. -Modifiers preceding a repeated definition apply to all constituent -definitions. The rules governing the validity and meaning of a -modifier are as follows. -\begin{itemize} -\item -The \verb@private@ modifier can be used with any definition in a -template. Private members can be accessed only from within the template -that defines them. -%Furthermore, accesses are not permitted in -%packagings (\sref{sec:topdefs}) other than the one containing the -%definition. -Private members are not inherited by subclasses and they -may not override definitions in parent classes. -\verb@private@ may not be applied to abstract members, and it -may not be combined in one modifier list with -\verb@protected@, \verb@final@ or \verb@override@. -\item -The \verb@protected@ modifier applies to class member definitions. -Protected members can be accessed from within the template of the defining -class as well as in all templates that have the defining class as a base class. -%Furthermore, accesses from the template of the defining class are not -%permitted in packagings other than the one -%containing the definition. -A protected identifier \verb@x@ may be used as -a member name in a selection \verb@r.x@ only if \verb@r@ is one of the reserved -words \verb@this@ and -\verb@super@, or if \verb@r@'s type conforms to a type-instance of the class -which contains the access. -\item -The \verb@override@ modifier applies to class member definitions. It -is mandatory for member definitions that override some other -non-abstract member definition in a super- or mixin-class. If an -\verb@override@ modifier is given, there must be at least one -overridden member definition. Furthermore, the overridden definition -must be concrete (\sref{sec:members}), unless the class containing the -overriding member is abstract. -\item -The \verb@abstract@ modifier is used in class definitions. It is -mandatory if the class has abstract members, or if the class has -members labeled \verb@override@ which override only abstract members -in a parent class. Classes with \verb@abstract@ members -cannot be instantiated (\sref{sec:inst-creation}) with a constructor -invocation unless followed by mixin constructors or statements which -override all abstract members of the class. -\item -The \verb@final@ modifier applies to class member definitions and to -class definitions. A \verb@final@ class member definition may not be -overridden in subclasses. A \verb@final@ class may not be inherited by -a template. \verb@final@ is redundant for object definitions. Members -of final classes or objects are implicitly also final, so the -\verb@final@ modifier is redundant for them, too. \verb@final@ may -not be applied to abstract members, and it may not be combined in one -modifier list with \verb@private@ or \verb@sealed@. -\item -The \verb@sealed@ modifier applies to class definitions. A -\verb@sealed@ class may not be inherited, except if either -\begin{itemize} -\item -the inheriting template is nested within the definition of the sealed -class itself, or -\item -the inheriting template belongs to a class or object definition which -forms part of the same statement sequence as the definition of the -sealed class. -\end{itemize} -\end{itemize} - -\example A useful idiom to prevent clients of a class from -constructing new instances of that class is to declare the class -\verb@abstract@ and \verb@sealed@: - -\begin{verbatim} -object m { - abstract sealed class C (x: Int) { - def nextC = C(x + 1) with {} - } - val empty = new C(0) {} -} -\end{verbatim} -For instance, in the code above clients can create instances of class -\verb@m.C@ only by calling the \verb@nextC@ method of an existing \verb@m.C@ -object; it is not possible for clients to create objects of class -\verb@m.C@ directly. Indeed the following two lines are both in error: - -\begin{verbatim} - m.C(0) \=// **** error: C is abstract, so it cannot be instantiated. - m.C(0) {} \>// **** error: illegal inheritance from sealed class. -\end{verbatim} - -\section{Class Definitions} -\label{sec:classes} - -\syntax\begin{verbatim} - ClsDef \=::=\= class ClassDef {`,' ClassDef} - ClassDef \>::=\> id [TypeParamClause] [ParamClause] [`:' SimpleType] - \> \> ClassTemplate - ClassTemplate \>::=\> extends Template - \> |\> TemplateBody - \> |\> -\end{verbatim} - -The most general form of class definition is -\verb@class c[tps](ps): s extends t@. -Here, -\begin{itemize} -\item[] -\verb@c@ is the name of the class to be defined. -\item[] \verb@tps@ is a non-empty list of type parameters of the class -being defined. The scope of a type parameter is the whole class -definition including the type parameter section itself. It is -illegal to define two type parameters with the same name. The type -parameter section \verb@[tps]@ may be omitted. A class with a type -parameter section is called {\em polymorphic}, otherwise it is called -{\em monomorphic}. -\item[] -\verb@ps@ is a formal parameter clause for the {\em primary -constructor} of the class. The scope of a formal parameter includes -the template \verb@t@. However, the formal parameter may not form -part of the types of any of the parent classes or members of \verb@t@. -It is illegal to define two formal parameters with the same name. -The formal parameter section \verb@(ps)@ may be omitted in which case -an empty parameter section \verb@()@ is assumed. -\item[] -\verb@s@ is the {\em self type} of the class. Inside the -class, the type of \verb@this@ is assumed to be \verb@s@. The self -type must conform to the self types of all classes which are inherited -by the template \verb@t@. The self type declaration `\verb@: s@' may be -omitted, in which case the self type of the class is assumed to be -equal to \verb@c[tps]@. -\item[] -\verb@t@ is a -template (\sref{sec:templates}) of the form -\verb@sc with mc$_1$ with ... with mc$_n$ { stats }@ -which defines the base classes, behavior and initial state of objects of -the class. The extends clause \verb@extends sc with ... with mc$_n$@ -can be omitted, in which case -\verb@extends scala.Object@ is assumed. The class body -\verb@{stats}@ may also be omitted, in which case the empty body -\verb@{}@ is assumed. -\end{itemize} -This class definition defines a type \verb@c[tps]@ and a constructor -which when applied to parameters conforming to types \verb@ps@ -initializes instances of type \verb@c[tps]@ by evaluating the template -\verb@t@. - -\subsection{Constructor Definitions} - -\syntax\begin{verbatim} - FunDef \=::=\= this ParamClause `=' ConstrExpr - ConstrExpr \>::=\> this ArgumentExpr - \> |\> `{' {BlockStat `;'} ConstrExpr `}' -\end{verbatim} - -A class may have additional constructors besides the primary -constructor. These are defined by constructor definitions of the form -\verb@def this(ps) = e@. Such a definition introduces an additional -constructor for the enclosing class, with parameters as given in the -formal parameter list \verb@ps@, and whose evaluation is defined by -the constructor expression \verb@e@. The scope of each formal -parameter is the constructor expression \verb@e@. A constructor -expression is either a self constructor invocation \verb@this(args)@ -or a block which ends in a constructor expression. In terms of -visibility rules, constructor definitions are conceptually outside -their enclosing class. Hence, they can access neither value -parameters nor members of the enclosing class by simple name, and the -value \verb@this@ refers to an object of the class enclosing the class -of the object being constructed. However, constructor definitions can -access type parameters of the enclosing class. - -If there are auxiliary constructors of a class \verb@C@, they define -together with \verb@C@'s primary constructor an overloaded constructor -value. The usual rules for overloading resolution -(\sref{sec:overloaded-defs}) apply for constructor invocations of \verb@C@, -including the self constructor invocations in the constructor -expressions themselves. To prevent infinite cycles of constructor -invocations, there is the restriction that every self constructor -invocation must refer to a constructor definition which precedes it -(i.e. it must refer to either a preceding auxiliary constructor or the -primary constructor of the class). The type of a constructor -expression must be always so that a generic instance of the class is -constructed. I.e., if the class in question has name \verb@C@ and type -parameters \verb@[tps]@, then each constructor must construct an -instance of \verb@C[tps]@; it is not permitted to instantiate formal -type parameters. - -\example Consider the class definition - -\begin{verbatim} -class LinkedList[a <: AnyRef](x: a, xs: LinkedList[a]) { - var head = x; - var tail = xs; - def isEmpty = tail != null; - def this() = this(null, null); - def this(x: a) = { val empty = new LinkedList(); this(x, empty) } -} -\end{verbatim} -This defines a class \verb@LinkedList@ with an overloaded constructor of type -\begin{verbatim} -[a <: AnyRef](x: a, xs: LinkList[a]): LinkedList[a] $\overload$ -[a <: AnyRef](): LinkedList[a] $\overload$ -[a <: AnyRef](x: a): LinkedList[a] . -\end{verbatim} -The second constructor alternative constructs an empty list, while the -third one constructs a list with one element. - -\subsection{Case Classes} -\label{sec:case-classes} - -\syntax\begin{verbatim} ClsDef \=::=\= case class ClassDef {`,' ClassDef} -\end{verbatim} - -If a class definition is prefixed with \verb@case@, the class is said -to be a {\em case class}. The primary constructor of a case class may -be used in a constructor pattern (\sref{sec:patterns}). That -constructor may not have any value parameters which are prefixed by -\verb@def@. None of the base classes of a case class may be a case -class. Furthermore, no type may have two different case classes among -its base types. - -A case class definition of \verb@c[tps](ps)@ with type -parameters \verb@tps@ and value parameters \verb@ps@ implicitly -generates a function definition for a {\em case class factory} -together with the class definition itself: -\begin{verbatim} -def c[tps](ps): s = new c[tps](ps) -\end{verbatim} -(Here, \verb@s@ s the self type of class \verb@c@. -If a type parameter section -is missing in the class, it is also missing in the factory -definition). - -Also implicitly defined are accessor member definitions -in the class that return its value parameters. Every binding -\verb@x: T@ in the parameter section leads to a value definition of -\verb@x@ that defines \verb@x@ to be an alias of the parameter. -%Every -%parameterless function binding \verb@def x: T@ leads to a -%parameterless function definition of \verb@x@ which returns the result -%of invoking the parameter function. -%The case class may not contain a -%directly bound member with the same simple name as one of its value -%parameters. - -Every case class implicitly overrides some method definitions of class -\verb@scala.Object@ (\sref{sec:cls-object}) unless a definition of the same -method is already given in the case class itself or a non-abstract -definition of the same method is given in some base class of the case -class different from \verb@Object@. In particular: -\begin{itemize} -\item[] Method \verb@equals: (Any)boolean@ is structural equality, where two -instances are equal if they belong to the same class and -have equal (with respect to \verb@equals@) primary constructor arguments. -\item[] Method \verb@hashCode: ()int@ computes a hash-code -depending on the data structure in a way which maps equal (with respect to -\verb@equals@) values to equal hash-codes. -\item[] Method \verb@toString: ()String@ returns a string representation which -contains the name of the class and its primary constructor arguments. -\end{itemize} - -\example Here is the definition of abstract syntax for lambda -calculus: - -\begin{verbatim} -class Expr; -case class - Var \=(x: String) \=extends Expr, - Apply \>(f: Expr, e: Expr) \>extends Expr, - Lambda \>(x: String, e: Expr) \>extends Expr; -\end{verbatim} -This defines a class \verb@Expr@ with case classes -\verb@Var@, \verb@Apply@ and \verb@Lambda@. A call-by-value evaluator for lambda -expressions could then be written as follows. - -\begin{verbatim} -type Env = String => Value; -case class Value(e: Expr, env: Env); - -def eval(e: Expr, env: Env): Value = e match { - case Var (x) => - env(x) - case Apply(f, g) => - val Value(Lambda (x, e1), env1) = eval(f, env); - val v = eval(g, env); - eval (e1, (y => if (y == x) v else env1(y))) - case Lambda(_, _) => - Value(e, env) -} -\end{verbatim} - -It is possible to define further case classes that extend type -\verb@Expr@ in other parts of the program, for instance -\begin{verbatim} -case class Number(x: Int) extends Expr; -\end{verbatim} - -This form of extensibility can be excluded by declaring the base class -\verb@Expr@ \verb@sealed@; in this case, the only classes permitted to -extend \verb@Expr@ are those which are nested inside \verb@Expr@, or -which appear in the same statement sequence as the definition of -\verb@Expr@. - -\section{Traits} - -\label{sec:traits} - -\syntax\begin{verbatim} - ClsDef \=::=\= trait ClassDef {`,' ClassDef} -\end{verbatim} - -A class definition which starts with the reserved word \verb@trait@ -instead of \verb@class@ defines a trait. A trait is a specific -instance of an abstract class, so the \verb@abstract@ modifier is -redundant for it. The template of a trait must satisfy the following -three restrictions. -\begin{enumerate} -\item All base classes of the trait are traits. -\item All parent class constructors of a template - must be primary constructors with empty value - parameter lists. -\item All non-empty statements in the template are either imports or pure definitions (\sref{sec:defs}). -\end{enumerate} -A {\em pure} definition can be evaluated without any side effect. -Function, type, class, or object definitions are always pure. A value -definition is pure if its right-hand side expression is pure. Pure -expressions are paths, literals, as well as typed expressions -\verb@e: T@ where \verb@e@ is pure. - -These restrictions ensure that the evaluation of the mixin constructor -of a trait has no effect. Therefore, traits may appear several times -in the base class sequence of a template, whereas other classes cannot. -%\item Packagings may add interface classes as new base classes to an -%existing class or module. - -\example\label{ex:comparable} -The following trait class defines the property of being -ordered, i.e. comparable to objects of some type. It contains an abstract method -\verb@<@ and default implementations of the other comparison operators -\verb@<=@, \verb@>@, and \verb@>=@. - -\begin{verbatim} -trait Ord[t <: Ord[t]]: t { - def < (that: t): Boolean; - def <=(that: t): Boolean = this < that || this == that; - def > (that: t): Boolean = that < this; - def >=(that: t): Boolean = that <= this; -} -\end{verbatim} - -\section{Object Definitions} -\label{sec:modules} -\label{sec:object-defs} - -\syntax\begin{verbatim} - ObjectDef \=::=\= id [`:' SimpleType] ClassTemplate -\end{verbatim} - -An object definition defines a single object of a new class. Its -most general is -\verb@object m: s extends t@. Here, -\begin{itemize} -\item[] -\verb@m@ is the name of the object to be defined. -\item[] \verb@s@ is the {\em self type} of the object. References to -\verb@m@ are assumed to have type \verb@s@. Furthermore, inside the -template \verb@t@, the type of \verb@this@ is also assumed to be \verb@s@. -The self type must conform to the self types of all classes which are -inherited by the template \verb@t@. The self type declaration -`\verb@:s@' may be omitted, in which case the self type of the class is -assumed to be equal to the anonymous class defined by \verb@t@. -\item[] -\verb@t@ is a -template (\sref{sec:templates}) of the form -\verb@sc with mc$_1$ with ... with mc$_n$ { stats }@ -which defines the base classes, behavior and initial state of \verb@m@. -The extends clause \verb@extends sc with ... with mc$_n$@ -can be omitted, in which case -\verb@extends scala.Object@ is assumed. The class body -\verb@{stats}@ may also be omitted, in which case the empty body -\verb@{}@ is assumed. -\end{itemize} -The object definition defines a single object (or: {\em module}) -conforming to the template \verb@t@. It is roughly equivalent to a class -definition and a value definition that creates an object of the class: -\begin{verbatim} -final class m$\Dollar$class: s extends t; -final val m: s = new m$\Dollar$class; -\end{verbatim} -(The \verb@final@ modifiers are omitted if the definition occurs as -part of a block. The class name \verb@m$\Dollar$class@ is not -accessible for user programs.) - -There are however two differences between an object definition and a -pair of class and value definition as the one given above. First, -object definitions may appear as top-level definitions in a -compilation unit, whereas value definitions may not. Second, the -module defined by an object definition is instantiated lazily. The -\verb@new m$\Dollar$class@ constructor is evaluated not at the point -of the object definition, but is instead evaluated the first time \verb@m@ -is dereferenced during execution of the program (which might be never -at all). An attempt to dereference \verb@m@ again in the course of -evaluation of the constructor leads to a infinite loop or run-time -error. Other threads trying to dereference \verb@m@ while the constructor -is being evaluated block until evaluation is complete. - -\example -Classes in Scala do not have static members; however, an equivalent -effect can be achieved by an accompanying object definition -E.g. -\begin{verbatim} -abstract class Point { - val x: Double; - val y: Double; - def isOrigin = (x == 0.0 && y == 0.0); -} -object Point { - val origin = new Point() with { val x = 0.0, y = 0.0 } -} -\end{verbatim} -This defines a class \verb@Point@ and an object \verb@Point@ which -contains \verb@origin@ as a member. Note that the double use of the -name \verb@Point@ is legal, since the class definition defines the name -\verb@Point@ in the type name space, whereas the object definition -defines a name in the term namespace. - -\comment{ -\example Here's an outline of a module definition for a file system. - -\begin{verbatim} -module FileSystem with { - private type FileDirectory; - private val dir: FileDirectory - - interface File with { - def read(xs: Array[Byte]) - def close: Unit - } - - private class FileHandle extends File with { ... } - - def open(name: String): File = ... -} -\end{verbatim} -} - -\chapter{Expressions} -\label{sec:exprs} - -\syntax\begin{verbatim} - Expr \=::=\= [Bindings `=>'] Expr - \> |\> if `(' Expr `)' Expr [[`;'] else Expr] - \> |\> try `{' block `}' [catch Expr] [finally Expr] - \> |\> while '(' Expr ')' Expr - \> |\> do Expr [`;'] while `(' Expr ')' - \> |\> for `(' Enumerators `)' (do | yield) Expr - \> |\> [SimpleExpr `.'] id `=' Expr - \> |\> SimpleExpr ArgumentExpr `=' Expr - \> |\> PostfixExpr [`:' Type1] - PostfixExpr \>::=\> InfixExpr [id] - InfixExpr \>::=\> PrefixExpr - \> |\> InfixExpr id InfixExpr - PrefixExpr \>::=\> [`-' | `+' | `~' | `!'] SimpleExpr - SimpleExpr \>::=\> literal - \> |\> Path - \> |\> `(' [Expr] `)' - \> |\> BlockExpr - \> |\> new Template - \> |\> SimpleExpr `.' id - \> |\> SimpleExpr TypeArgs - \> |\> SimpleExpr ArgumentExpr - ArgumentExpr \>::=\> `(' Expr ')' - \> |\> BlockExpr - BlockExpr \>::=\> `{' CaseClause {CaseClause} `}' - \> |\> `{' Block `}' - Block \>::=\> {BlockStat `;'} [Expr] - Exprs \>::= \> Expr {`,' Expr} -\end{verbatim} - -Expressions are composed of operators and operands. Expression forms are -discussed subsequently in decreasing order of precedence. - -The typing of expressions is often relative to some {\em expected -type}. When we write ``expression \verb@e@ is expected to conform to -type \verb@T@'', we mean: (1) the expected type of \verb@e@ is -\verb@T@, and (2) the type of expression \verb@e@ must conform to -\verb@T@. - -\section{Literals} - -\syntax\begin{verbatim} - SimpleExpr \=::= \= literal - literal \>::= \> intLit - \> |\> floatLit - \> |\> charLit - \> |\> stringLit - \> |\> symbolLit -\end{verbatim} - -Typing and evaluation of numeric, character, and string literals are -generally as in Java. An integer literal denotes an integer -number. Its type is normally \verb@int@. However, if the expected type -\verb@pt@ of the expression is either \verb@byte@, \verb@short@, or -\verb@char@ and the integer number fits in the numeric range defined -by the type, then the number is converted to type \verb@pt@ and the -expression's type is \verb@pt@. A floating point literal denotes a -single-precision or double precision IEEE floating point number. A -character literal denotes a Unicode character. A string literal -denotes a member of \verb@java.lang.String@. - -A symbol literal \verb@'id@ is a shorthand for the expression -\verb@scala.Symbol("id")@. If the symbol literal is followed by an -actual parameters, as in \verb@'id(args)@, then the whole expression -is taken to be a shorthand for -\verb@scala.Labelled(scala.Symbol("id"), args)@. - -\section{Boolean constants} - -\begin{verbatim} - SimpleExpr \=::= \= true | false -\end{verbatim} - -The boolean truth values are denoted by the reserved words \verb@true@ -and \verb@false@. The type of these expressions is \verb@boolean@, and -their evaluation is immediate. - -\section{The $\NULL$ Reference} - -\syntax\begin{verbatim} - SimpleExpr \=::= \= null -\end{verbatim} - -The \verb@null@ expression is of type \verb@scala.AllRef@. It -denotes a reference value which refers to a special ``null' object, -which implements methods in class \verb@scala.AnyRef@ as follows: -\begin{itemize} -\item[] -\verb@eq(x)@, \verb@==(x)@, \verb@equals(x)@ return \verb@true@ iff their -argument \verb@x@ is also the ``null'' object. -\item[] -\verb@isInstanceOf[T]@ always returns \verb@false@. -\item[] -\verb@asInstanceOf[T]@ always returns the ``null'' object itself. -\item[] -\verb@toString@ returns the string ``null''. -\end{itemize} -A reference to any other member of the ``null'' object causes a -\verb@NullPointerException@ to be thrown. - -\section{Designators} -\label{sec:designators} - -\syntax\begin{verbatim} - Designator \=::= \= Path - \> | \> SimpleExpr `.' id -\end{verbatim} - -A designator refers to a named term. It can be a {\em simple name} or -a {\em selection}. If $r$ is a stable identifier of type $T$, the -selection $r.x$ refers to the term member of $r$ that is identified in -$T$ by the name $x$. For other expressions $e$, $e.x$ is typed as if -it was $(\VAL;y=e\semi y.x)$ for some fresh name $y$. The typing rules -for blocks implies that in that case $x$'s type may not refer to any -abstract type member of \verb@e@. - -The expected type of a designator's prefix is always missing. -The -type of a designator is normally the type of the entity it refers -to. However, if the designator is a path (\sref{sec:paths}) \verb@p@, -its type is \verb@p.type@, provided the expression's expected type is -a singleton type, or \verb@p@ occurs as the prefix of a selection, -type selection, or mixin super expression. - -The selection $e.x$ is evaluated by first evaluating the qualifier -expression $e$. The selection's result is then the value to which the -selector identifier is bound in the selected object designated by $e$. - -\section{This and Super} -\label{sec:this-super} - -\syntax\begin{verbatim} - SimpleExpr \=::= \= [id `.'] this - \> | \> [id `.'] super [`[' id `]'] `.' id -\end{verbatim} - -The expression \verb@this@ can appear in the statement part of a -template or compound type. It stands for the object being defined by -the innermost template or compound type enclosing the reference. If -this is a compound type, the type of \verb@this@ is that compound type. -If it is a template of an instance creation expression, the type of -\verb@this@ is the type of that template. If it is a template of a -class or object definition with simple name \verb@C@, the type of this -is the same as the type of \verb@C.this@. - -The expression \verb@C.this@ is legal in the statement part of an -enclosing class or object definition with simple name \verb@C@. It -stands for the object being defined by the innermost such definition. -If the expression's expected type is a singleton type, or -\verb@C.this@ occurs as the prefix of a selection, its type is -\verb@C.this.type@, otherwise it is the self type of class \verb@C@. - -A reference \verb@super.m@ in a template refers to the definition of -\verb@m@ in the actual superclass (\sref{sec:base-classes}) of the -template. A reference \verb@C.super.m@ refers to the definition of -\verb@m@ in the actual superclass of the innermost enclosing class or -object definition named \verb@C@ which encloses the reference. The -definition referred to by \verb@super@ or \verb@C.super@ must be -concrete, or the template containing the reference must contain a -definition which has an \verb@override@ modifier and which overrides -\verb@m@. - -The \verb@super@ prefix may be followed by a mixin qualifier -\verb@[M]@, as in \verb@C.super[M].x@. This is called a {\em mixin -super reference}. In this case, the reference is to the member of -\verb@x@ in the (first) mixin class of \verb@C@ whose simple name -is \verb@M@. - -\example\label{ex:super} -Consider the following class definitions - -\begin{verbatim} -class Root { val x = "Root" } -class A extends Root { override val x = "A" ; val superA = super.x } -class B extends Root { override val x = "B" ; val superB = super.x } -class C extends A with B with { override val x = "C" ; val superC = super.x } -class D extends A with { val superD = super.x } -class E extends C with D with { val superE = super.x } -\end{verbatim} -Then we have: -\begin{verbatim} -new A.superA = "Root", new B.superB = "Root" -new C.superA = "Root", new C.superB = "A", new C.superC = "A" -new D.superA = "Root", new D.superD = "A" -new E.superA = "Root", new E.superB = "A", new E.superC = "A", - new E.superD = "C", new E.superE = "C" -\end{verbatim} -Note that the \verb@superB@ function returns different results -depending on whether \verb@B@ is used as defining class or as a mixin class. - -\example Consider the following class definitions: -\begin{verbatim} -class Shape { - override def equals(other: Any) = ...; - ... -} -trait Bordered extends Shape { - val thickness: int; - override def equals(other: Any) = other match { - case that: Bordered => this.thickness == that.thickness - case _ => false - } - ... -} -trait Colored extends Shape { - val color: Color; - override def equals(other: Any) = other match { - case that: Colored => this.color == that.color - case _ => false - } - ... -} -\end{verbatim} - -All three definitions of \verb@equals@ are combined in the class -below, which makes use of both plain and mixin super references. -\begin{verbatim} -trait BorderedColoredShape extends Shape with Bordered with Colored { - override def equals(other: Any) = other match { - case that: BorderedColoredShape => - super.equals(that) && - super[Bordered].equals(that) && - super[Colored].equals(that) - case _ => false - } -} -\end{verbatim} - -\section{Function Applications} -\label{sec:apply} - -\syntax\begin{verbatim} - SimpleExpr \=::= \= SimpleExpr ArgumentExpr -\end{verbatim} - -An application \verb@f(e$_1$, ..., e$_n$)@ applies the function \verb@f@ to the -argument expressions \verb@e$_1$, ..., e$_n$@. If \verb@f@ has a method type -\verb@(T$_1$, ..., T$_n$)U@, the type of each argument -expression \verb@e$_i$@ must conform to the corresponding parameter type -\verb@T$_i$@. If \verb@f@ has some value type, the application is taken to be -equivalent to \verb@f.apply(e$_1$, ..., e$_n$)@, i.e.\ the -application of an \verb@apply@ function defined by \verb@f@. - -%Class constructor functions -%(\sref{sec:classes}) can only be applied in constructor invocations -%(\sref{sec:constr-invoke}), never in expressions. - -Evaluation of \verb@f(e$_1$, ..., e$_n$)@ usually entails evaluation of -\verb@f@ and \verb@e$_1$, ..., e$_n$@ in that order. Each argument expression -is converted to the type of its corresponding formal parameter. After -that, the application is rewritten to the function's right hand side, -with actual arguments substituted for formal parameters. The result -of evaluating the rewritten right-hand side is finally converted to -the function's declared result type, if one is given. - -The case of a formal \verb@def@-parameter with a parameterless -method type \verb@[]T@ is treated specially. In this case, the -corresponding actual argument expression is not evaluated before the -application. Instead, every use of the formal parameter on the -right-hand side of the rewrite rule entails a re-evaluation of the -actual argument expression. In other words, the evaluation order for -\verb@def@-parameters is {\em call-by-name} whereas the evaluation -order for normal parameters is {\em call-by-value}. - -\section{Type Applications} -\label{sec:type-app} -\syntax\begin{verbatim} - SimpleExpr \=::= \= SimpleExpr `[' Types `]' -\end{verbatim} - -A type application \verb@e[T$_1$, ..., T$_n$]@ instantiates a -polymorphic value \verb@e@ of type -\verb@[a$_1$ >: L$_1$ <: U$_1$, ..., a$_n$ >: L$_n$ <: U$_n$]S@ with -argument types \verb@T$_1$, ..., T$_n$@. Every argument type -\verb@T$_i$@ must obey corresponding bounds \verb@L$_i$@ and -\verb@U$_i$@. That is, for each \verb@i = 1, ..., n@, we must -have \verb@L$_i \sigma$ <: T$_i$ <: U$_i \sigma$@, where $\sigma$ is the -substitution \verb@[a$_1$ := T$_1$, ..., a$_n$ := T$_n$]@. The type -of the application is \verb@S$\sigma$@. - -The function part \verb@e@ may also have some value type. In this case -the type application is taken to be equivalent to -\verb@e.apply[T$_1$, ..., T$_n$]@, i.e.\ the -application of an \verb@apply@ function defined by \verb@e@. - -Type applications can be omitted if local type inference -(\sref{sec:local-type-inf}) can infer best type parameters for a -polymorphic functions from the types of the actual function arguments -and the expected result type. - -\section{References to Overloaded Bindings} -\label{sec:overloaded-refs} - -If a name \verb@f@ referenced in an identifier or selection is -overloaded (\sref{sec:overloaded-types}), the context of the reference -has to identify a unique alternative of the overloaded binding. The -way this is done depends on whether or not \verb@f@ is used as a -function. Let $\AA$ be the set of all type alternatives of -\verb@f@. - -Assume first that \verb@f@ appears as a function in an application, as -in \verb@f(args)@. If there is precisely one alternative in -$\AA$ which is a (possibly polymorphic) method type whose arity -matches the number of arguments given, that alternative is chosen. - -Otherwise, let \verb@argtypes@ be the vector of types obtained by -typing each argument with a missing expected type. One determines -first the set of applicable alternatives. A method type alternative is -{\em applicable} if each type in \verb@argtypes@ is compatible with -the corresponding formal parameter type in the alternative, and, if -the expected type is defined, the method's result type is compatible to -it. A polymorphic method type is applicable if local type inference -can determine type arguments so that the instantiated method type is -applicable. - -Here, a type \verb@T@ is {\em compatible} to a type \verb@U@ if one of the -following three clauses applies: -\begin{enumerate} -\item -\verb@T@ conforms to \verb@U@. -\item -\verb@T@ is a parameterless method type \verb@[]T'@ and \verb@T'@ -conforms to \verb@U@. -\item -\verb@T@ is a monomorphic method type \verb@(Ts$_1$) ... (Ts$_n$)S@ which -can be converted to a function type \verb@T'@ by using the rules for -implicit conversions (\sref{sec:impl-conv}) and \verb@T'@ conforms to -\verb@U@. -\end{enumerate} - -Let $\BB$ be the set of applicable alternatives. It is an error if -$\BB$ is empty. Otherwise, one chooses the {\em most specific} -alternative among the alternatives in $\BB$, according to the -following definition of being ``more specific''. -\begin{itemize} -\item -A method type \verb@(Ts)U@ is more specific than some other -type \verb@S@ if \verb@S@ is applicable to arguments \verb@(ps)@ of -types \verb@Ts@. -\item -A polymorphic method type -\verb@[a$_1$ >: L$_1$ <: U$_1$, ..., a$_n$ >: L$_n$ <: U$_n$]T@ is -more specific than some other type \verb@S@ if \verb@T@ is more -specific than \verb@S@ under the assumption that for -\verb@i = 1, ..., n@ each \verb@a$_i$@ is an abstract type name -bounded from below by \verb@L$_i$@ and from above by \verb@U$_i$@. -\item -Any other type is always more specific than a parameterized method -type or a polymorphic type. -\end{itemize} -It is an error if there is no unique alternative in $\BB$ which is -more specific than all other alternatives in $\BB$. - -Assume next that \verb@f@ appears as a function in a type -application, as in \verb@f[targs]@. Then we choose an alternative in -$\AA$ which takes the same number of type parameters as there are -type arguments in \verb@targs@. It is an error if no such alternative -exists, or if it is not unique. - -Assume finally that \verb@f@ does not appear as a function in either -an application or a type application. If an expected type is given, -let $\BB$ be the set of those alternatives in $\AA$ which are -compatible to it. Otherwise, let $\BB$ be the same as $\AA$. -We choose in this case the most specific alternative among all -alternatives in $\BB$. It is an error if there is no unique -alternative in $\BB$ which is more specific than all other -alternatives in $\BB$. - -\example Consider the following definitions: - -\begin{verbatim} - class A extends B {} - def f(x: B, y: B) = ... - def f(x: A, y: B) = ... - val a: A, b: B -\end{verbatim} -Then the application \verb@f(b, b)@ refers to the first -definition of \verb@f@ whereas the application \verb@f(a, a)@ -refers to the second. Assume now we add a third overloaded definition -\begin{verbatim} - def f(x: B, y: A) = ... -\end{verbatim} -Then the application \verb@f(a, a)@ is rejected for being ambiguous, since -no most specific applicable signature exists. - -\section{Instance Creation Expressions} -\label{sec:inst-creation} - -\syntax\begin{verbatim} - SimpleExpr \=::= \= new Template -\end{verbatim} - -A simple instance creation expression is \verb@new c@ where \verb@c@ -is a constructor invocation (\sref{sec:constr-invoke}). Let \verb@T@ -be the type of \verb@c@. Then \verb@T@ must denote a (a type instance -of) a non-abstract subclass of \verb@scala.AnyRef@ which -conforms to its self type. The expression is evaluated by creating a -fresh object of the type \verb@T@, which is is initialized by -evaluating \verb@c@. The type of the expression is \verb@T@'s self -type (which might be less specific than \verb@T@). - -A general instance creation expression is -\verb@new sc with mc$_1$ with ... with mc$_n$ {stats}@ where -\verb@n $\geq$ 0@, \verb@sc@ as well as \verb@mc$_1$, ..., mc$_n$@ are -constructor invocations (of types \verb@S, T$_1$, ...,T$_n$@, say) and -\verb@stats@ is a statement sequence containing initializer statements -and member definitions (\sref{sec:members}). The type of such an -instance creation expression is then the compound type -\verb@S with T$_1$ with ... with T$_n$ {R}@, where \verb@{R}@ is a -refinement (\sref{sec:compound-types}) which declares exactly those -members of \verb@stats@ that override a member of \verb@S@ or -\verb@T$_1$, ..., T$_n$@. For this type to be well-formed, \verb@R@ -may not reference types defined in \verb@stats@ which do not -themselves form part of \verb@R@. - -The instance creation expression is evaluated by creating a fresh -object, which is initialized by evaluating the expression template. - -\example Consider the class -\begin{verbatim} -abstract class C { - type T; val x: T; def f(x: T): Object -} -\end{verbatim} -and the instance creation expression -\begin{verbatim} -C { type T = Int; val x: T = 1; def f(x: T): T = y; val y: T = 2 } -\end{verbatim} -Then the created object's type is: -\begin{verbatim} -C { type T = Int; val x: T; def f(x: T): T } -\end{verbatim} -The value \verb@y@ is missing from the type, since \verb@y@ does not -override a member of \verb@C@. - -\section{Blocks} -\label{sec:blocks} - -\syntax\begin{verbatim} - BlockExpr \=::= \= `{' Block `}' - Block \>::= \> [{BlockStat `;'} Expr] -\end{verbatim} - -A block expression \verb@{s$_1$; ...; s$_n$; e}@ is constructed from a -sequence of block statements \verb@s$_1$ , ..., s$_n$@ and a final -expression \verb@e@. The final expression can be omitted, in which -case the unit value \verb@()@ is assumed. - -%Whether or not the scope includes the statement itself -%depends on the kind of definition. - -The expected type of the final expression \verb@e@ is the expected -type of the block. The expected type of all preceding statements is -missing. - -The type of a block \verb@s$_1$; ...; s$_n$; e@ is usually the type of -\verb@e@. That type must be equivalent to a type which does not refer -to an entity defined locally in the block. If this condition is -violated, but a fully defined expected type is given, the type of the -block is instead assumed to be the expected type. - -Evaluation of the block entails evaluation of its statement sequence, -followed by an evaluation of the final expression \verb@e@, which -defines the result of the block. - -\example -Written in isolation, -the block \verb@{ class C extends B {...} ; new C }@ is illegal, since its type -refers to class \verb@C@, which is defined locally in the block. - -However, when used in a definition such as -\begin{verbatim} -val x: B = { class C extends B {...} ; new C } -\end{verbatim} -the block is well-formed, since the problematic type \verb@C@ can be -replaced by the expected type \verb@B@. - -\section{Prefix, Infix, and Postfix Operations} -\label{sec:infix-operations} - -\syntax\begin{verbatim} - PostfixExpr \=::=\= InfixExpr [id] - InfixExpr \>::=\> PrefixExpr - \> |\> InfixExpr id InfixExpr - PrefixExpr \>::=\> [`-' | `+' | `!' | `~'] SimpleExpr -\end{verbatim} - -Expressions can be constructed from operands and operators. A prefix -operation \verb@op e@ consists of a prefix operator \verb@op@, which -must be one of the identifiers `\verb@+@', `\verb@-@', `\verb@!@', or -`\verb@~@', and a simple expression \verb@e@. The expression is -equivalent to the postfix method application \verb@e.op@. - -Prefix operators are different from normal function applications in -that their operand expression need not be atomic. For instance, the -input sequence \verb@-sin(x)@ is read as \verb@-(sin(x))@, whereas the -function application \verb@negate sin(x)@ would be parsed as the -application of the infix operator \verb@sin@ to the operands -\verb@negate@ and \verb@(x)@. - -An infix or postfix operator can be an arbitrary identifier. Binary -operators have precedence and associativity defined as follows: - -The {\em precedence} of an operator is determined by the operator's first -character. Characters are listed below in increasing order of -precedence, with characters on the same line having the same precedence. -\begin{verbatim} - (all letters) - | - ^ - & - < > - = ! - : - + - - * / % - (all other special characters) -\end{verbatim} -That is, operators starting with a letter have lowest precedence, -followed by operators starting with `\verb@|@', etc. - -The {\em associativity} of an operator is determined by the operator's -last character. Operators ending with a colon `\verb@:@' are -right-associative. All other operators are left-associative. - -Precedence and associativity of operators determine the grouping of -parts of an expression as follows. -\begin{itemize} -\item If there are several infix operations in an -expression, then operators with higher precedence bind more closely -than operators with lower precedence. -\item If there are consecutive infix -operations \verb@e$_0$ op$_1$ e$_1$ op$_2$ ... op$_n$ e$_n$@ -with operators \verb@op$_1$, ..., op$_n$@ of the same precedence, -then all these operators must -have the same associativity. If all operators are left-associative, -the sequence is interpreted as -\verb@(...(e$_0$ op$_1$ e$_1$) op$_2$...) op$_n$ e$_n$@. -Otherwise, if all operators are right-associative, the -sequence is interpreted as -\verb@e$_0$ op$_1$ (e$_1$ op$_2$ (... op$_n$ e$_n$)...)@. -\item -Postfix operators always have lower precedence than infix -operators. E.g.\ \verb@e$_1$ op$_1$ e$_2$ op$_2$@ is always equivalent to -\verb@(e$_1$ op$_1$ e$_2$) op$_2$@. -\end{itemize} -A postfix operation \verb@e op@ is interpreted as \verb@e.op@. A -left-associative binary operation \verb@e$_1$ op e$_2$@ is interpreted as -\verb@e$_1$.op(e$_2$)@. If \verb@op@ is right-associative, the same operation is -interpreted as \verb@(val x=e$_1$; e$_2$.op(x))@, -where \verb@x@ is a fresh name. - -\section{Typed Expressions} - -\syntax\begin{verbatim} - Expr \=::= \= PostfixExpr [`:' Type1] -\end{verbatim} - -The typed expression \verb@e: T@ has type \verb@T@. The type of -expression \verb@e@ is expected to conform to \verb@T@. The result of -the expression is the value of \verb@e@ converted to type \verb@T@. - -\example Here are examples of well-typed and illegal typed expressions. - -\begin{verbatim} - 1: int \=// legal, of type int - 1: long \>// legal, of type long - // 1: string \>// illegal -\end{verbatim} - -\section{Assignments} - -\syntax\begin{verbatim} - Expr \=::= \= Designator `=' Expr - \> | \> SimpleExpr ArgumentExpr `=' Expr -\end{verbatim} - -An assignment to a simple variable \verb@x = e@ is interpreted -depending on whether \verb@x@ is defined in a block or in a -template. If \verb@x@ is a variable defined in a block, then the -assignment changes the current value of \verb@x@ to be the result of -evaluating the expression \verb@e@. The type of \verb@e@ is expected -to conform to the type of \verb@x@. If \verb@x@ is a member -of a template, the assignment \verb@x = e@ is interpreted as the -invocation \verb@x_=(e)@ of the setter function for variable \verb@x@ -(\sref{sec:vardef}). Analogously, an assignment \verb@f.x = e@ to a -field \verb@x@ is interpreted as the invocation \verb@f.x_=(e)@. - -An assignment \verb@f(args) = e@ with a function application to the -left of the ``\verb@=@' operator is interpreted as -\verb@f.update(args, e)@, i.e.\ -the invocation of an \verb@update@ function defined by \verb@f@. - -\example \label{ex:imp-mat-mul} -Here is the usual imperative code for matrix multiplication. - -\begin{verbatim} -def matmul(xss: Array[Array[double]], yss: Array[Array[double]]) = { - val zss: Array[Array[double]] = new Array(xss.length, yss.length); - var i = 0; - while (i < xss.length) { - var j = 0; - while (j < yss(0).length) { - var acc = 0.0; - var k = 0; - while (k < yss.length) { - acc = acc + xs(i)(k) * yss(k)(j); - k = k + 1 - } - zss(i)(j) = acc; - j = j + 1 - } - i = i + 1 - } - zss -} -\end{verbatim} -Desugaring the array accesses and assignments yields the following -expanded version: -\begin{verbatim} -def matmul(xss: Array[Array[double]], yss: Array[Array[double]]) = { - val zss: Array[Array[double]] = new Array(xss.length, yss.length); - var i = 0; - while (i < xss.length) { - var j = 0; - while (j < yss(0).length) { - var acc = 0.0; - var k = 0; - while (k < yss.length) { - acc = acc + xss.apply(i).apply(k) * yss.apply(k).apply(j); - k = k + 1 - } - zss.apply(i).update(j, acc); - j = j + 1 - } - i = i + 1 - } - zss -} -\end{verbatim} - -\section{Conditional Expressions} - -\syntax\begin{verbatim} - Expr \=::= \= if `(' Expr `)' Expr [[`;'] else Expr] -\end{verbatim} - -The conditional expression \verb@if (e$_1$) e$_2$ else e$_3$@ chooses -one of the values of \verb@e$_2$@ and \verb@e$_2$@, depending on the -value of \verb@e$_1$@. The condition \verb@e$_1$@ is expected to -conform to type \verb@boolean@. The then-part \verb@e$_2$@ and the -else-part \verb@e$_3$@ are both expected to conform to the expected -type of the conditional expression. The type of the conditional -expression is the least upper bound of the types of \verb@e$_1$@ and -\verb@e$_2$@. A semicolon preceding the \verb@else@ symbol of a -conditional expression is ignored. - -The conditional expression is evaluated by evaluating first -\verb@e$_1$@. If this evaluates to \verb@true@, the result of -evaluating \verb@e$_2$@ is returned, otherwise the result of -evaluating \verb@e$_3$@ is returned. - -A short form of the conditional expression eliminates the -else-part. The conditional expression \verb@if (e$_1$) e$_2$@ is -evaluated as if it was \verb@if (e$_1$) e$_2$ else ()@. The type of -this expression is \verb@unit@ and the then-part -\verb@e$_2$@ is also expected to conform to type \verb@unit@. - -\section{While Loop Expressions} - -\syntax\begin{verbatim} - Expr \=::= \= while `(' Expr ')' Expr -\end{verbatim} - -The while loop expression \verb@while (e$_1$) e$_2$@ is typed and -evaluated as if it was an application of \verb@whileLoop (e$_1$) (e$_2$)@ where -the hypothetical function \verb@whileLoop@ is defined as follows. - -\begin{verbatim} - def whileLoop(def c: boolean)(def s: unit): unit = - if (c) { s ; while(c)(s) } else {} -\end{verbatim} - -\example The loop -\begin{verbatim} - while (x != 0) { y = y + 1/x ; x = x - 1 } -\end{verbatim} -Is equivalent to the application -\begin{verbatim} - whileLoop (x != 0) { y = y + 1/x ; x = x - 1 } -\end{verbatim} -Note that this application will never produce a division-by-zero -error at run-time, since the -expression \verb@(y = 1/x)@ will be evaluated in the body of -\verb@while@ only if the condition parameter is false. - -\section{Do Loop Expressions} - -\syntax\begin{verbatim} - Expr \=::= \= do Expr [`;'] while `(' Expr ')' -\end{verbatim} - -The do loop expression \verb@do e$_1$ while (e$_2$)@ is typed and -evaluated as if it was the expression \verb@(e$_1$ ; while (e$_2$) e$_1$)@. -A semicolon preceding the \verb@while@ symbol of a do loop expression is ignored. - -\section{Comprehensions} - -\syntax\begin{verbatim} - Expr \=::= \= for `(' Enumerators `)' (do | yield) Expr - Enumerator \>::=\> Generator {`;' Enumerator} - Enumerator \>::=\> Generator - \> |\> Expr - Generator \>::=\> val Pattern `<-' Expr -\end{verbatim} - -A comprehension \verb@for (ens) yield e@ evaluates expression \verb@e@ for each -binding generated by the enumerators \verb@ens@. An enumerator is a generator, -possibly followed by further generators or filters. A generator -\verb@val p <- e@ produces bindings from an expression \verb@e@ which is -matched in some way against pattern \verb@p@. Filters are expressions which -restrict enumerated bindings. The precise meaning of generators and -filters is defined by translation to invocations of four methods: -\verb@map@, \verb@filter@, \verb@flatMap@, and \verb@foreach@. These -methods can be implemented in different ways for different carrier -types. As an example, an implementation of these methods for lists is -given in \sref{cls-list}. - -The translation scheme is as follows. -In a first step, every generator \verb@val p <- e@, where \verb@p@ is not -a pattern variable, is replaced by -\begin{verbatim} -val p <- e.filter { case p => true; case _ => false } -\end{verbatim} -Then, the following -rules are applied repeatedly until all comprehensions have been eliminated. -\begin{itemize} -\item -A generator \verb@q <- e@ followed by a filter \verb@f@ is translated to -a single generator \verb@q <- e.filter(x$_1$, ..., x$_n$ => f)@ where -\verb@x$_1$, ..., x$_n$@ are the free variables of \verb@q@. - -\item -A for-comprehension -\verb@for (val p <- e) yield e'@ -is translated to -\verb@e.map { case p => e' }@. - -\item -A for-comprehension -\verb@for (val p <- e) do e'@ -is translated to -\verb@e.foreach { case p => e' }@. - -\item -A for-comprehension -\begin{verbatim} -for (val p <- e; val p' <- e' ...) yield e'' , -\end{verbatim} -where \verb@...@ is a (possibly empty) -sequence of generators or filters, -is translated to -\begin{verbatim} -e.flatmap { case p => for (val p' <- e' ...) yield e'' } . -\end{verbatim} -\item -A for-comprehension -\begin{verbatim} -for (val p <- e; val p' <- e' ...) do e'' . -\end{verbatim} -where \verb@...@ is a (possibly empty) -sequence of generators or filters, -is translated to -\begin{verbatim} -e.foreach { case p => for (val p' <- e'...) do e'' } . -\end{verbatim} -\end{itemize} - -\example -the following code produces all pairs of numbers -between \verb@1@ and \verb@n-1@ whose sums are prime. -\begin{verbatim} -for \= { \= val i <- range(1, n); - \> \> val j <- range(1, i); - \> \> isPrime(i+j) -} yield Pair (i, j) -\end{verbatim} -The for-comprehension is translated to: -\begin{verbatim} -range(1, n) - .flatMap { - case i => range(1, i) - .filter { j => isPrime(i+j) } - .map { case j => Pair(i, j) } } -\end{verbatim} - -\comment{ -\example -\begin{verbatim} -package class List[a] with { - def map[b](f: (a)b): List[b] = match { - case <> => <> - case x :: xs => f(x) :: xs.map(f) - } - def filter(p: (a)Boolean) = match { - case <> => <> - case x :: xs => if p(x) then x :: xs.filter(p) else xs.filter(p) - } - def flatMap[b](f: (a)List[b]): List[b] = - if (isEmpty) Nil - else f(head) ::: tail.flatMap(f); - } - def foreach(f: (a)Unit): Unit = - if (isEmpty) () - else (f(head); tail.foreach(f)); -} -\end{verbatim} - -\example -\begin{verbatim} -abstract class Graph[Node] { - type Edge = (Node, Node) - val nodes: List[Node] - val edges: List[Edge] - def succs(n: Node) = for ((p, s) <- g.edges, p == n) s - def preds(n: Node) = for ((p, s) <- g.edges, s == n) p -} -def topsort[Node](g: Graph[Node]): List[Node] = { - val sources = for (n <- g.nodes, g.preds(n) == <>) n - if (g.nodes.isEmpty) <> - else if (sources.isEmpty) new Error(``topsort of cyclic graph'') throw - else sources :+: topsort(new Graph[Node] with { - val nodes = g.nodes diff sources - val edges = for ((p, s) <- g.edges, !(sources contains p)) (p, s) - }) -} -\end{verbatim} -} - -\example For comprehensions can be used to express vector -and matrix algorithms concisely. -For instance, here is a function to compute the transpose of a given matrix: - -\begin{verbatim} -def transpose[a](xss: Array[Array[a]]) { - for (val i <- Array.range(0, xss(0).length)) yield - Array(for (val xs <- xss) yield xs(i)) -\end{verbatim} - -Here is a function to compute the scalar product of two vectors: -\begin{verbatim} -def scalprod(xs: Array[double], ys: Array[double]) { - var acc = 0.0; - for (val Pair(x, y) <- xs zip ys) do acc = acc + x * y; - acc -} -\end{verbatim} - -Finally, here is a function to compute the product of two matrices. Compare with the imperative version of \ref{ex:imp-mat-mul}. -\begin{verbatim} -def matmul(xss: Array[Array[double]], yss: Array[Array[double]]) = { - val ysst = transpose(yss); - for (val xs <- xs) yield - for (val yst <- ysst) yield - scalprod(xs, yst) -} -\end{verbatim} -The code above makes use of the fact that \verb@map@, \verb@flatmap@, -\verb@filter@, and \verb@foreach@ are defined for members of class -\verb@scala.Array@. - -\section{Try Expressions} - -\syntax\begin{verbatim} - Expr \=::= \= try `{' block `}' [catch Expr] [finally Expr] -\end{verbatim} - -A try expression \verb@try { b } catch e@ evaluates the block -\verb@b@. If evaluation of \verb@b@ does not cause an exception to be -thrown, the result of \verb@b@ is returned. Otherwise the {\em -handler} \verb@e@ is applied to the thrown exception. Let \verb@pt@ -be the expected type of the try expression. The block \verb@b@ is -expected to conform to \verb@pt@. The handler \verb@e@ is expected -conform to type \verb@scala.PartialFunction[scala.Throwable, pt]@. -The type of the try expression is the least upper bound of the type of -\verb@b@ and the result type of \verb@e@. - -A try expression \verb@try { b } finally e@ evaluates the block -\verb@b@. If evaluation of \verb@b@ does not cause an exception to be -thrown, expression \verb@e@ is evaluated. If an exception is thrown -during evaluation of \verb@e@, the evaluation of the try expression is -aborted with the thrown exception. If no exception is thrown during -evaluation of \verb@e@, the result of \verb@b@ is returned as the -result of the try expression. If an exception is thrown during -evaluation of \verb@b@, the finally block -\verb@e@ is also evaluated. If another exception \verb@e@ is thrown -during evaluation of \verb@e@, evaluation of the try expression is -aborted with the thrown exception. If no exception is thrown during -evaluation of \verb@e@, the original exception thrown in \verb@b@ is -re-thrown once evaluation of \verb@e@ has completed. The block -\verb@b@ is expected to conform to the expected type of the try -expression. The finally expression \verb@e@ is expected to conform to -type \verb@unit@. - -A try expression \verb@try { b } catch e$_1$ finally e$_2$@ is a shorthand -for \verb@try { try { b } catch e$_1$ } finally e$_2$@. - -\section{Anonymous Functions} -\label{sec:closures} - -\syntax\begin{verbatim} - Expr \=::= \= [Bindings `=>'] Expr - Bindings \>::=\> `(' Binding {`,' Binding `)' - \> |\> id [`:' Type1] - Binding \>::= \> id [`:' Type] -\end{verbatim} - -The anonymous function \verb@(x$_1$: T$_1$, ..., x$_n$: T$_n$) => e@ -maps parameters \verb@x$_i$@ of types \verb@T$_i$@ to a result given -by expression \verb@e@. The scope of each formal parameter -\verb@x$_i$@ is \verb@e@. - -If the expected type of the anonymous function is of the form -\verb@scala.Function$\,n$[S$_1$, ..., S$_n$, R]@, the expected types -of \verb@e@ is \verb@R@ and the type \verb@T$_i$@ of any of the -parameters \verb@x$_i$@ can be omitted, in which case -\verb@T$_i$ = S$_i$@ is assumed. If the expected type of the anonymous -function is some other type, all formal parameter types must be -explicitly given, and the expected type of \verb@e@ is missing. The -type of the anonymous function is -\verb@scala.Function$\,n$[S$_1$, ..., S$_n$, T]@, where \verb@T@ is -the type of \verb@e@. \verb@T@ must be equivalent to a type which does -not refer to any of the formal parameters \verb@x$_i$@. - -The anonymous function is evaluated as the instance creation expression -\begin{verbatim} -scala.Function$\,n$[T$_1$, ..., T$_n$, T] { - def apply(x$_1$: T$_1$, ..., x$_n$: T$_n$): T = e -} -\end{verbatim} -In the case of a single formal parameter, \verb@(x: T) => e@ and \verb@(x) => e@ -can be abbreviated to \verb@x: T => e@, and \verb@x => e@, respectively. - -\example Examples of anonymous functions: - -\begin{verbatim} - x => x \=// The identity function - - f => g => x => f(g(x)) \>// Curried function composition - - (x: Int,y: Int) => x + y \>// A summation function - - () => { count = count + 1; count } \>// The function which takes an empty - \>// parameter list $()$, increments a non-local - \>// variable count and returns the new value. -\end{verbatim} - -\section{Statements} -\label{sec:statements} - -\syntax\begin{verbatim} - BlockStat \=::= \= Import - \> | \> Def - \> | \> {LocalModifier} ClsDef - \> | \> Expr - \> | \> - TemplateStat \>::= \> Import - \> | \> {Modifier} Def - \> | \> {Modifier} Dcl - \> | \> Expr - \> | \> -\end{verbatim} - -Statements occur as parts of blocks and templates. A statement can be -an import, a definition or an expression, or it can be empty. -Statements used in the template of a class definition can also be -declarations. An expression that is used as a statement can have an -arbitrary value type. An expression statement $e$ is evaluated by -evaluating $e$ and discarding the result of the evaluation. - -Block statements may be definitions which bind local names in the -block. The only modifiers allowed in block-local definitions are modifiers -\verb@abstract@, \verb@final@, or \verb@sealed@ preceding a class or -object definition. - -With the exception of overloaded definitions -(\sref{sec:overloaded-defs}), a statement sequence making up a block -or template may not contain two definitions or declarations that bind -the same name in the same namespace. Evaluation of a statement -sequence entails evaluation of the statements in the order they are -written. - -\chapter{Pattern Matching} - -\section{Patterns} - -% 2003 July - changed to new pattern syntax + semantic Burak - -\label{sec:patterns} - -\syntax\begin{verbatim} -Pattern \=::= \= TreePattern { `|' TreePattern } - -TreePattern \>::= \> varid `:' Type - \> | \> `_' `:' Type - \> | \> SimplePattern [ '*' | '?' | '+' ] - \> | \> SimplePattern { id SimplePattern } - -SimplePattern \=::= \> varid [ '@' SimplePattern ] - \> | \> `_' - \> | \> literal - \> | \> StableId [ `(' [Patterns] `)' ] - \> | \> `(' Patterns `)' - \> | \> - - Patterns \>::= \> Pattern {`,' Pattern} -\end{verbatim} - -A pattern is built from constants, constructors, variables and regular -operators. Pattern matching tests whether a given value (or sequence -of values) has the shape defined by a pattern, and, if it does, binds -the variables in the pattern to the corresponding components of the -value (or sequence of values). The same variable name may not be -bound more than once in a pattern. - -The type of a pattern and the expected types of variables within the -pattern are determined by the context, except for patterns -that employ regular operators. In the latter case the missing -information is provided by the structure of the pattern. -We distinguish the following kinds of patterns. - -A {\em wild-card pattern} \_ matches any value. - -A {\em variable-binding pattern} $x @ p$ is a simple identifier $x$ -which starts with a lower case letter, together with a pattern $p$. It -matches a value or a sequence of values whenever $p$ does, and in -addition binds the variable name to that value or to that sequence of -values. The type of $x$ is either $T$ as determined from the context, or -\verb@List[T]@ \todo{really?}, if $p$ matches sequences of values. A -special case is a {\em variable pattern} $x$ which is treated as $x @ \_$. - -A {\em typed pattern} $x: T$ consists of a pattern variable $x$ and a -simple type $T$. The type $T$ may be a class type or a compound type; -it may not contain a refinement (\sref{sec:refinements}). This -pattern matches any non-null value of type $T$ and binds the variable -name to that value. $T$ must conform to the pattern's expected -type. The type of $x$ is $T$. - -A {\em pattern literal} $l$ matches any value that is equal (in terms -of $==$) to it. It's type must conform to the expected type of the -pattern. - -A {\em named pattern constant} $p$ is a stable identifier -(\sref{sec:stableids}). To resolve the syntactic overlap with a -variable pattern, a named pattern constant may not be a simple name -starting with a lower-case letter. The stable identifier $p$ is -expected to conform to the expected type of the pattern. The pattern -matches any value $v$ such that \verb@$r$ == $v$@ -(\sref{sec:cls-object}). - -A {\em sequence pattern} $p_1 \commadots p_n$ where $n \geq 0$ is a -sequence of patterns separated by commas and matching the sequence of -values that are matched by the components. Sequence pattern may only -appear under constructor applications. Note that empty sequence -patterns are allowed. The type of the value patterns \todo{where defined?} -that appear in -the pattern is the expected type as determined from the context. - -A {\em choice pattern} $p_1 | \ldots | p_n$ is a choice among several -alternatives, which may not contain variable-binding patterns. It -matches every value matched by at least one of its alternatives. Note -that the empty sequence may appear as an alternative. An {\em option -pattern} $p?$ is an abbreviation for $(p| )$. If the alternatives -are value patterns, then the whole choice pattern is a value pattern, -whose type is the least upper bound of the types of the alternatives. - -An {\em iterated pattern} $p*$ matches the sequence of values -consisting of zero, one or more occurrences of values matched by $p$, -where $p$ may not contain a variable-binding pattern. A {\em non-empty -iterated pattern} $p+$ is an abbreviation for $(p,p*)$. - -A non-regular sequence \todo{find other term?} -pattern is a sequence pattern $p_1 \commadots p_n$ -where $n \geq 1$ with no component pattern containing iterated or nested -sequence patterns. - -A {\em constructor pattern} $c ( p )$ consists of a simple type $c$ -followed by a pattern $p$. If $c$ designates a monomorphic case -class, then it must conform to the expected type of the pattern, the -pattern must be a non-regular sequence pattern $p_1 \commadots p_n$ -whose length corresponds to the number of arguments of $c$'s primary -constructor. The expected types of the component patterns are then -taken from the formal parameter types of (said) constructor. If $c$ -designates a polymorphic case class, then there must be a unique type -application instance of it such that the instantiation of $c$ conforms -to the expected type of the pattern. The instantiated formal parameter -types of $c$'s primary constructor are then taken as the expected -types of the component patterns $p_1\commadots p_n$. In both cases, -the pattern matches all objects created from constructor invocations -$c(v_1 \commadots v_n)$ where each component pattern $p_i$ matches the -corresponding value $v_i$. If $c$ does not designate a case class, it -must be a subclass of \verb@Seq[ T ]@. In that case $p$ may be an -arbitrary pattern. Value patterns in $p$ are expected to conform to -type $T$, and the pattern matches all objects whose \verb@elements()@ -method returns a sequence that matches $p$. - -The pattern $(p)$ is regarded as equivalent to the pattern $p$, if $p$ -is a nonempty sequence pattern. The empty tuple $()$ is a shorthand -for the constructor pattern \verb@Unit@. - -An {\em infix operation pattern} \verb@p id p'@ is a shorthand for the -constructor pattern \verb@id(p, p')@. The precedence and -associativity of operators in patterns is the same as in expressions -(\sref{sec:infix-operations}). The operands may not be empty sequence -patterns. - -Regular expressions that contain variable bindings may be ambiguous, -i.e. there might be several ways to match a sequence against the -pattern. In these cases, the \emph{shortest-match policy} applies: -patterns that appear before other, overlapping patterns match -as little as possible. - -\example Some examples of patterns are: -\begin{enumerate} -\item -The pattern \verb@ex: IOException@ matches all instances of class -\verb@IOException@, binding variable \verb@ex@ to the instance. -\item -The pattern \verb@Pair(x, _)@ matches pairs of values, binding \verb@x@ to -the first component of the pair. The second component is matched -with a wildcard pattern. -\item -The pattern \verb+List( x, y, xs @ _ * )+ matches lists of length $\geq 2$, -binding \verb@x@ to the list's first element, \verb@y@ to the list's -second element, and \verb@xs@ to the remainder, which may be empty. -\item -The pattern \verb=List( 1, x@(( 'a' | 'b' )+),y,_ )= matches a list that -contains 1 as its first element, continues with a non-empty sequence of -\verb@'a'@s and \verb@'b'@s, followed by two more elements. The sequence 'a's and 'b's -is bound to \verb@x@, and the next to last element is bound to \verb@y@. -\item -The pattern \verb=List( x@( 'a'* ), 'a'+ )= matches a non-empty list of -\verb@'a'@s. Because of the shortest match policy, \verb@x@ will always be bound to -the empty sequence. -\item -The pattern \verb=List( x@( 'a'+ ), 'a'* )= also matches a non-empty list of -\verb@'a'@s. Here, \verb@x@ will always be bound to -the sequence containing one \verb@'a'@ -\end{enumerate} - -\subsection{Pattern Matching Expressions} -\label{sec:pattern-match} - -\syntax\begin{verbatim} - BlockExpr \=::=\= `{' CaseClause {CaseClause} `}' - CaseClause \>::=\> case Pattern [`if' PostfixExpr] `=>' Block -\end{verbatim} - -A pattern matching expression -\verb@case p$_1$ => b$_1$ ... case p$_n$ => b$_n$@ consists of a number -$n \geq 1$ of cases. Each case consists of a (possibly guarded) pattern -$p_i$ and a block $b_i$. The scope of the pattern variables in $p_i$ is -the corresponding block $b_i$. - -The expected type of a pattern matching expression must in part be -defined. It must be either \verb@scala.Function1[T$_p$, T$_r$]@ or -\verb@scala.PartialFunction[T$_p$, T$_r$]@, where the argument type -\verb@T$_p$@ must be fully determined, but the result type -\verb@T$_r$@ may be undetermined. All patterns are typed -relative to the expected type $T_p$ (\sref{sec:patterns}). The expected type of -every block \verb@b$_i$@ is \verb@T$_r$@. -Let \verb@T$_b$@ be the least upper bound of the types of all blocks -\verb@b$_i$@. The type of the pattern matching expression is -then the required type with \verb@T$_r$@ replaced by \verb@T$_b$@ -(i.e. the type is either \verb@scala.Function[T$_p$, T$_b$]@ or -\verb@scala.PartialFunction[T$_p$, T$_b$]@. - -When applying a pattern matching expression to a selector value, -patterns are tried in sequence until one is found which matches the -selector value (\sref{sec:patterns}). Say this case is $\CASE;p_i -\Arrow b_i$. The result of the whole expression is then the result of -evaluating $b_i$, where all pattern variables of $p_i$ are bound to -the corresponding parts of the selector value. If no matching pattern -is found, a \verb@scala.MatchError@ exception is thrown. - -The pattern in a case may also be followed by a guard suffix \verb@if e@ -with a boolean expression $e$. The guard expression is evaluated if -the preceding pattern in the case matches. If the guard expression -evaluates to \verb@true@, the pattern match succeeds as normal. If the -guard expression evaluates to \verb@false@, the pattern in the case -is considered not to match and the search for a matching pattern -continues. - -\comment{ -A case with several patterns $\CASE;p_1 \commadots p_n ;\IF; e \Arrow b$ is a -shorthand for a sequence of single-pattern cases $\CASE;p_1;\IF;e \Arrow b -;\ldots; \CASE;p_n ;\IF;e\Arrow b$. In this case none of the patterns -$p_i$ may contain a named pattern variable (but the patterns may contain -wild-cards). -} - -In the interest of efficiency the evaluation of a pattern matching -expression may try patterns in some other order than textual -sequence. This might affect evaluation through -side effects in guards. However, it is guaranteed that a guard -expression is evaluated only if the pattern it guards matches. - -\example -Often, pattern matching expressions are used as arguments -of the \verb@match@ method, which is predefined in class \verb@Any@ -(\sref{sec:cls-object}) and is implemented there by postfix function -application. Here is an example: -\begin{verbatim} -def length [a] (xs: List[a]) = xs match { - case Nil => 0 - case x :: xs1 => 1 + length (xs1) -} -\end{verbatim} - -\chapter{Top-Level Definitions} -\label{sec:topdefs} - -\syntax\begin{verbatim} - CompilationUnit \=::=\= [package QualId `;'] {TopStat `;'} TopStat - TopStat \>::=\> {Modifier} ClsDef - \> |\> Import - \> |\> Packaging - \> |\> - QualId \>::=\> id {`.' id} -\end{verbatim} - -A compilation unit consists of a sequence of packagings, import -clauses, and class and object definitions, which may be preceded by a -package clause. - -A compilation unit \verb@package p; stats@ starting with a package -clause is equivalent to a compilation unit consisting of a single -packaging \verb@package p { stats }@. - -Implicitly imported into every compilation unit are, in that order: -the package \verb@java.lang@, the package \verb@scala@, and the object -\verb@scala.Predef@ (\sref{cls-predef}). Members of a later import in -that order hide members of an earlier import. - -\section{Packagings} - -\syntax\begin{verbatim} - Packaging \=::= \= package QualId `{' {TopStat `;'} TopStat `}' -\end{verbatim} - -A package is a special object which defines a set of member classes, -objects and packages. Unlike other objects, packages are not introduced -by a definition. Instead, the set of members of a package is determined by -packagings. - -A packaging \verb@package p { ds }@ injects all definitions in -\verb@ds@ as members into the package whose qualified name is -\verb@p@. If a definition in \verb@ds@ is labeled \verb@private@, it -is visible only for other members in the package. - -Selections \verb@p.m@ from \verb@p@ as well as imports from \verb@p@ -work as for objects. However, unlike other objects, packages may not -be used as values. It is illegal to have a package with the same fully -qualified name as a module or a class. - -Top-level definitions outside a packaging are assumed to be injected -into a special empty package. That package cannot be named and -therefore cannot be imported. However, members of the empty package -are visible to each other without qualification. - -\example The following example will create a hello world program as -function \verb@main@ of module \verb@test.HelloWorld@. -\begin{verbatim} -package test; - -object HelloWord { - def main(args: Array[String]) = System.out.println("hello world") -} -\end{verbatim} - -\end{document} - -\chapter{Local Type Inference} -\label{sec:local-type-inf} - -This needs to be specified in detail. -Essentially, similar to what is done for GJ. - -\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. -} - -\chapter{The Scala Standard Library} - -The Scala standard library consists of the package \verb@scala@ with a -number of classes and modules. - -\section{Root Classes} -\label{sec:cls-root} -\label{sec:cls-any} -\label{sec:cls-object} - -The root of the Scala class hierarchy is formed by class \verb@Any@. -Every class in a Scala execution environment inherits directly or -indirectly from this class. Class \verb@Any@ has exactly two direct -subclasses: \verb@AnyRef@ and\verb@AnyVal@. - -The subclass \verb@AnyRef@ represents all values which are represented -as objects in the underlying host system. The type of the \verb@null@ -value copnforms to every subclass of \verb@AnyRef@. A direct subclass -of -\verb@AnyRef@ is class \verb@Object@. Every user-defined Scala -class inherits directly or indirectly from this class. Classes written -in other languages still inherit from \verb@scala.AnyRef@, but not -necessarily from \verb@scala.Object@. - -The class \verb@AnyVal@ has a fixed number subclasses, which describe -values which are not implemented as objects in the underlying host -system. - -Classes \verb@AnyRef@ and \verb@AnyVal@ are required to provide only -the members declared in class \verb@Any@, but implementations may add -host-specific methods to these classes (for instance, an -implementation may identify class \verb@AnyRef@ with its own root -class for objects). - -The standard interfaces of these root classes is described by the -following definitions. - -\begin{verbatim} -abstract class Any with { - /** Get runtime type descriptor */ - def getType: Type = ... - - /** Reference equality */ - def eq (that: Any): Boolean = ... - - /** Hash code */ - def def hashCode: Int = ... -\end{verbatim} -\begin{verbatim} - /** Type test */ - def is [a]: Boolean = ... - - /** Type cast */ - def as[a]: a = if (is[a]) ... else new CastException() throw - - /** Semantic equality between values of same type */ - def == (that: Any): Boolean = this equals that - - /** Semantic inequality between values of same type */ - def != (that: Any): Boolean = !(this == that) - - /** Semantic equality between arbitrary values */ - def equals (that: Any): Boolean = ... - - /** Representation as string */ - def toString: String = getType.toString ++ "@" ++ hashCode - - /** Concatenation of string representations */ - final def + (that: Any) = toString.concat(that) - - /** Pattern matching application */ - final def match [a] (f: (Any)a): a = f(this) -} -final class AnyVal extends Any -class AnyRef extends Any -class Object extends AnyRef -\end{verbatim} - - -\section{Value Classes} -\label{sec:cls-value} - -Value classes are classes whose instances are not represented as -objects by the underlying host system. All value classes inherit from -class \verb@AnyVal@. Scala implementations need to provide the -following value classes (but are free to provide others as well). - -\begin{verbatim} -final class Unit extends AnyVal with { ... } -final class Boolean extends AnyVal with { ... } -final class Double extends AnyVal with { ... } -final class Float extends Double with { ... } -final class Long extends Float with { ... } -final class Int extends Long with { ... } -final class Char extends Int with { ... } -final class Short extends Int with { ... } -final class Byte extends Short with { ... } -\end{verbatim} - -These classes are defined in the following. - -\subsection{Class \prog{Double}} - -\begin{verbatim} -final class Double extends AnyVal with Ord with { - def asDouble: Double \=// convert to Double - def asFloat: Float \>// convert to Float - def asLong: Long \>// convert to Long - def asInt: Int \>// convert to Int - def asChar: Char \>// convert to Char - def asShort: Short \>// convert to Short - def asByte: Byte \>// convert to Byte - - def + (that: Double): Double \>// double addition - def - (that: Double): Double \>// double subtraction - def * (that: Double): Double \>// double multiplication - def / (that: Double): Double \>// double division - def % (that: Double): Double \>// double remainder - - def == (that: Double): Boolean \>// double equality - def != (that: Double): Boolean \>// double inequality - def < (that: Double): Boolean \>// double less - def > (that: Double): Boolean \>// double greater - def <= (that: Double): Boolean \>// double less or equals - def >= (that: Double): Boolean \>// double greater or equals - - def - : Double = 0.0 - this \>// double negation - def + : Double = this -} -\end{verbatim} - -\subsection{Class \prog{Float}} - -\begin{verbatim} -final class Float extends Double with { - def asDouble: Double \=// convert to Double - def asFloat: Float \>// convert to Float - def asLong: Long \>// convert to Long - def asInt: Int \>// convert to Int - def asChar: Char \>// convert to Char - def asShort: Short \>// convert to Short - def asByte: Byte \>// convert to Byte - - def + (that: Double): Double = asDouble + that - def + (that: Float): Double \>// float addition - /* analogous for -, *, /, % */ - - def == (that: Double): Boolean = asDouble == that - def == (that: Float): Boolean \>// float equality - /* analogous for !=, <, >, <=, >= */ - - def - : Float = 0.0f - this \>// float negation - def + : Float = this -} -\end{verbatim} - -\subsection{Class \prog{Long}} - -\begin{verbatim} -final class Long extends Float with { - def asDouble: Double \=// convert to Double - def asFloat: Float \>// convert to Float - def asLong: Long \>// convert to Long - def asInt: Int \>// convert to Int - def asChar: Char \>// convert to Char - def asShort: Short \>// convert to Short - def asByte: Byte \>// convert to Byte - - def + (that: Double): Double = asDouble + that - def + (that: Float): Double = asFloat + that - def + (that: Long): Long = \>// long addition - /* analogous for -, *, /, % */ - - def << (cnt: Int): Long \>// long left shift - def >> (cnt: Int): Long \>// long signed right shift - def >>> (cnt: Int): Long \>// long unsigned right shift - def & (that: Long): Long \>// long bitwise and - def | (that: Long): Long \>// long bitwise or - def ^ (that: Long): Long \>// long bitwise exclusive or - - def == (that: Double): Boolean = asDouble == that - def == (that: Float): Boolean = asFloat == that - def == (that: Long): Boolean \>// long equality - /* analogous for !=, <, >, <=, >= */ - - def - : Long = 0l - this \>// long negation - def + : Long = this -} -\end{verbatim} - - -\subsection{Class \prog{Int}} - -\begin{verbatim} -class Int extends Long with { - def asDouble: Double \=// convert to Double - def asFloat: Float \>// convert to Float - def asLong: Long \>// convert to Long - def asInt: Int \>// convert to Int - def asChar: Char \>// convert to Char - def asShort: Short \>// convert to Short - def asByte: Byte \>// convert to Byte - - def + (that: Double): Double = asDouble + that - def + (that: Float): Double = asFloat + that - def + (that: Long): Long = \>// long addition - def + (that: Int): Int = \>// long addition - /* analogous for -, *, /, % */ - - def << (cnt: Int): Int \>// long left shift - /* analogous for >>, >>> */ - - def & (that: Long): Long = asLong & that - def & (that: Int): Int \>// bitwise and - /* analogous for |, ^ */ - - def == (that: Double): Boolean = asDouble == that - def == (that: Float): Boolean = asFloat == that - def == (that: Long): Boolean \>// long equality - /* analogous for !=, <, >, <=, >= */ - - def - : Long = 0l - this \>// long negation - def + : Long = this -} -\end{verbatim} - -\subsection{Class \prog{Boolean}} -\label{sec:cls-boolean} - -\begin{verbatim} -abstract final class Boolean extends AnyVal with Ord with { - def ifThenElse[a](def t: a)(def e: a): a - - def ifThen(def t: Unit): Unit = ifThenElse(t)() - - def && (def x: Boolean): Boolean = ifThenElse(x)(False) - def || (def x: Boolean): Boolean = ifThenElse(True)(x) - def ! (def x: Boolean): Boolean = ifThenElse(False)(True) - - def == (x: Boolean): Boolean = ifThenElse(x)(x.!) - def != (x: Boolean): Boolean = ifThenElse(x.!)(x) - def < (x: Boolean): Boolean = ifThenElse(False)(x) - def > (x: Boolean): Boolean = ifThenElse(x.!)(False) - def <= (x: Boolean): Boolean = ifThenElse(x)(True) - def >= (x: Boolean): Boolean = ifThenElse(True)(x.!) -} -case class True extends Boolean with { def ifThenElse(t)(e) = t } -case class False extends Boolean with { def ifThenElse(t)(e) = e } -\end{verbatim} - - -\comment{ -\section{Reflection} - -\subsection{Classes \prog{Type}, \prog{Class}, \prog{CompoundType}} - -\begin{verbatim} -class Type[A] with { - def isSubType [B] (that: Type[B]): Boolean = ... -} -\end{verbatim} - -\begin{verbatim} -class Class[A] extends Type[A] with { - ... -} -\end{verbatim} - -\begin{verbatim} -abstract class CompoundType[A] extends Type[A] with { - def components: List[Class[A]] - ... -} -\end{verbatim} -} -\section{Other Standard Classes} - -\subsection{Class \prog{Unit} and the \prog{Tuple} Classes} -\label{sec:cls-tuple} - -\begin{verbatim} -case class Unit with { - def toString = "()" -} -case class Tuple$\,n$[a$_1$, ..., a$_n$](x$_1$: a$_1$, ..., x$_n$: a$_n$) with { - def $\_1$: a$_1$ = x$_1$ - ... - def $\_n$: a$_n$ = x$_n$ - def toString = "(" ++ x$_1$ ++ "," ++ ... ++ x$_n$ ++ ")" -} -\end{verbatim} - -\subsection{The \prog{Function} Classes} -\label{sec:cls-function} - -\begin{verbatim} -class Function$\,n$[a$_1$, ..., a$_n$,b] with { - // some methods in Any are overwritten - def apply(x$_1$: a$_1$, ..., x$_n$: a$_n$): b -} -\end{verbatim} -Class \verb@Function1@ additionally defines the method -\begin{verbatim} - def o [c] (f: Function1[c,a$_1$]): Function1[c,b] = x: c => apply(f(x)) -\end{verbatim} -There is also a module \verb@Function@, defined as follows. -\begin{verbatim} -module Function { - def compose[a](fs: List[(a)a]): (a)a = { - x => fs match { - case Nil => x - case f :: fs1 => compose(fs1)(f(x)) - } - } -} -\end{verbatim} -A subclass of \verb@Function$\,n$@ describes partial functions, which -are undefined on some points in their domain. - -\begin{verbatim} -class PartialFunction$\,n$[a$_1$, ..., a$_n$,b] extends Function$\,n$[a$_1$, ..., a$_n$,b] with { - def isDefined(x$_1$: a$_1$, ..., x$_n$: a$_n$): Boolean -} -\end{verbatim} - -In addition to the \verb@apply@ method of functions, partial functions -also have a \verb@isDefined@ method, which tells whether the function -is defined at the given argument. - -Classes \verb@Function@ and \verb@PartialFunction@ are defined to be aliases for -\verb@Function1@ and \verb@PartialFunction1@: -\begin{verbatim} - type Function[a,b] = Function1[a,b] - type PartialFunction[a,b] = PartialFunction1[a,b] - def Function[a,b]: class Function1[a,b] = Function1[a,b] - def PartialFunction[a,b]: class PartialFunction1[a,b] = PartialFunction1[a,b] -\end{verbatim} - -\subsection{Class \prog{List}}\label{cls-list} - -\begin{verbatim} -abstract class List[a] with { - abstract def isEmpty: Boolean; - abstract def head: a; - abstract def tail: List[a]; - - def ::(x: a): List[a] = - new ::_class(x)(this); - - def :::(prefix: List[a]): List[a] = - if (prefix.isEmpty) this - else prefix.head :: (prefix.tail ::: this); - - def length: Int = { - this match { - case [] => 0 - case _ :: xs => xs.length + 1} - } -\end{verbatim} -\begin{verbatim} - def init: List[a] = - if (isEmpty) error("Nil.init") - else if (tail.isEmpty) Nil - else head :: tail.init; - - def last: a = - if (isEmpty) error("Nil.last") - else if (tail.isEmpty) head - else tail.last; - - def take(n: Int): List[a] = - if (n == 0) Nil - else head :: tail.take(n-1); - - def drop(n: Int): List[a] = - if (n == 0) this - else tail.drop(n-1); - - def takeWhile(p: (a)Boolean): List[a] = - if (isEmpty || !p(head)) Nil - else head :: tail.takeWhile(p); - - def dropWhile(p: (a)Boolean): List[a] = - if (isEmpty || !p(head)) this - else tail.dropWhile(p); - - def at(n: Int) = drop(n).head; -\end{verbatim} -\begin{verbatim} - def map[b](f: (a)b): List[b] = - if (isEmpty) Nil - else f(head) :: tail.map(f); - - def foreach(f: (a)Unit): Unit = - if (isEmpty) () - else (f(head); tail.foreach(f)); - - def filter(p: (a)Boolean): List[a] = - if (isEmpty) this - else if (p(head)) head :: tail.filter(p) - else tail.filter(p); - - def forall(p: (a)Boolean): Boolean = - isEmpty || (p(head) && tail.forall(p)); - - def exists(p: (a)Boolean): Boolean = - !isEmpty && (p(head) || tail.exists(p)); -\end{verbatim} -\begin{verbatim} - def :_foldl[b](z: b)(f: (b, a)b) = match { - case [] => z - case x :: xs => (f(z, x) :_foldl xs)(f) - } - - def foldr[b](z: b)(f: (a, b)b) = match { - case [] => z - case x :: xs => f(x, (xs foldr z)(f)) - } - - def redl(f: (a, a)a) = match { - case [] => error("redl of empty list") - case x :: xs => (x :_foldl xs)(f) - } - - def redr(f: (a, a)a): a = match { - case [] => error("redr of empty list") - case [x] => x - case x :: xs => f(x, xs redr f) - } -\end{verbatim} -\begin{verbatim} - def flatMap[b](f: (a)List[b]): List[b] = - if (isEmpty) Nil - else f(head) ::: tail.flatMap(f); - - def reverse: List[a] = { - def snoc(xs: List[a], x: a): List[a] = x :: xs; - fold(snoc)(Nil) - } - - def print: Unit = - if (isEmpty) System.out.println("[]") - else { - System.out.print(head.as[java.lang.Object]); - System.out.print(" :: "); - tail.print - } - - def toArray: Array[a] = { - val xs = new Array[a](length); - copyToArray(xs, 0); - xs - } - - def copyToArray(xs: Array[a], start: Int): Int = { - xs(start) = head; - tail.copyToArray(xs, start + 1) - } -\end{verbatim} -\begin{verbatim} - def mkString(start: String, sep: String, end: String): String = - start + - (if (isEmpty) end - else if (tail.isEmpty) head.toString() + end - else head.toString().concat(sep).concat(tail.mkString("", sep, end))); - - def zip[b](that: List[b]): List[(a,b)] = - if (this.isEmpty || that.isEmpty) Nil - else (this.head, that.head) :: this.tail.zip(that.tail); -\end{verbatim} -\begin{verbatim} - def contains(elem: a) = exists(x => x == elem); - - def union(that: List[a]): List[a] = - if (this.isEmpty) that - else { - val result = this.tail union that; - if (that contains this.head) result else this.head :: result; - } - - def diff(that: List[a]): List[a] = - if (that.isEmpty) this - else { - val result = this.tail diff that; - if (that contains this.head) result else this.head :: result; - } - - def intersect(that: List[a]): List[a] = filter(x => that contains x); - - def removeDuplicates: List[a] = - if (isEmpty) this - else { - val rest = tail.removeDuplicates; - if (rest contains head) rest else head :: rest - } -} -\end{verbatim} -\begin{verbatim} -final case class ::_class[b](hd: b)(tl: List[b]) extends List[b] with { - def isEmpty = False; - def head = hd; - def tail = tl; - override def toString(): String = mkString("[", ",", "]"); -} -\end{verbatim} -\begin{verbatim} -final case class Nil[c] extends List[c] with { - def isEmpty = True; - def head: c = error("head of empty list"); - def tail: List[c] = error("tail of empty list"); - override def toString(): String = "[]"; -} -\end{verbatim} - -\subsection{Class \prog{Array}} - -The class of generic arrays is defined as follows. - -\begin{verbatim} -class Array[a](l: int) extends Function[Int, a] with { - def length: int = l - def apply(i: Int): a = ... - def update(i: Int)(x: a): Unit = ... -} -\end{verbatim} -\comment{ -\begin{verbatim} -module Array { - def create[a](i1: Int): Array[a] = Array[a](i1) - def create[a](i1: Int, i2: Int): Array[Array[a]] = { - val x: Array[Array[a]] = create(i1) - 0 to (i1 - 1) do { i => x(i) = create(i2) } - x - } - ... - def create[a](i1: Int, i2: Int, i3: Int, i4: Int, i5: Int, - i6: Int, i7: Int, i8: Int, i9: Int, i10: Int) - : Array[Array[Array[Array[Array[Array[Array[Array[Array[Array[a]]]]]]]]]] = { - val x: Array[Array[Array[Array[Array[Array[Array[Array[Array[a]]]]]]]]] = create(i1) - 0 to (i1 - 1) do { i => x(i) = create(i2, i3, i4, i5, i6, i7, i8, i9, i10) } - x - } -} -\end{verbatim} -} -\section{Exceptions} -\label{sec:exceptions} - -There is a predefined type \verb@Throwable@, as well as functions to -throw and handle values of type \verb@Throwable@. These are declared -as follows. - -\begin{verbatim} - class Throwable with { - def throw[a]: a - } - class ExceptOrFinally[a] with { - def except (handler: PartialFunction[Throwable,a]): a - def finally (def handler: Unit): a - } - def try [a] (def body: a): ExceptOrFinally[a] -\end{verbatim} - -The type \verb@Throwable@ represents exceptions and error objects; it -may be identified with an analogous type of the underlying -implementation such as \verb@java.lang.Throwable@. We will in the -following loosely call values of type \verb@Throwable@ exceptions. - -The \verb@throw@ method in \verb@Throwable@ aborts execution of the -thread executing it and passes the thrown exception to the handler -that was most recently installed by a -\verb@try@ function in the current thread. If no \verb@try@ method is -active, the thread terminates. - -The \verb@try@ function executes its body with the given exception -handler. A \verb@try@ expression comes in two forms. The first form is - -\begin{verbatim} -try $body$ except $handler$ . -\end{verbatim} - -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 \verb@handler@ is defined, -the handler is invoked with the thrown exception as argument. - -The second form of a try expression is - -\begin{verbatim} -try $body$ finally $handler$ . -\end{verbatim} - -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 \verb@Unit@ as result type. -If execution of the handler expression throws an exception, this -exception is propagated out of the \verb@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 \verb@try@ expression. - -\example An example of a try-except expression: - -\begin{verbatim} -try { - System.in.readString() -} except { - case ex: EndOfFile => "" -} -\end{verbatim} - -\example An example of a try-finally expression: - -\begin{verbatim} -file = open (fileName) -if (file != null) { - try { - process (file) - } finally { - file.close - } -} -\end{verbatim} - -\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 \verb@Thread@ for run-time threads, -\verb@fork@ function to spawn off a new thread, -as well as \verb@Monitor@ and \verb@Signal@ classes. These are -specified as follows\nyi{Concurrentcy constructs are}. - - -\begin{verbatim} -class Thread with { ... } -def fork (def p: Unit): Thread -\end{verbatim} - -The \verb@fork@ function runs its argument computation \verb@p@ in a -separate thread. It returns the thread object immediately to its -caller. Unhandled exceptions (\sref{sec:exceptions}) thrown during -evaluation of \verb@p@ abort execution of the forked thread and are -otherwise ignored. - -\begin{verbatim} -class Monitor with { - def synchronized [a] (def e: a): a -} -\end{verbatim} - -Monitors define a \verb@synchronized@ method which provides mutual -exclusion between threads. It executes its argument computation -\verb@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{verbatim} -class Signal with { - def wait: Unit - def wait(msec: Long): Unit - def notify: Unit - def notifyAll: Unit -} -\end{verbatim} - -The \verb@Signal@ class provides the basic means for process -synchronization. The \verb@wait@ method of a signal suspends the -calling thread until it is woken up by some future invocation of the -signal's \verb@notify@ or \verb@notifyAll@ method. The \verb@notify@ -method wakes up one thread that is waiting for the signal. The -\verb@notifyAll@ method wakes up all threads that are waiting for the -signal. A second version of the \verb@wait@ method takes a time-out -parameter (given in milliseconds). A thread calling \verb@wait(msec)@ -will suspend until unblocked by a \verb@notify@ or \verb@notifyAll@ -method, or until the \verb@msec@ millseconds have passed. - -\subsection{Channels} - -\begin{verbatim} -class Channel[a] with { - def write(x: a): Unit - def read: a -} -\end{verbatim} - -An object of type \verb@Channel[a]@ Channels offer a write-operation -which writes data of type \verb@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 -\verb@Message@ class. -There is a special message \verb@TIMEOUT@ which is used to signal a time-out. -\begin{verbatim} -class Message -case class TIMEOUT extends Message -\end{verbatim} -Message spaces implement the following class. -\begin{verbatim} -class MessageSpace with { - def send(msg: Message): Unit - def receive[a](f: PartialFunction1[Message, a]): a - def receiveWithin[a](msec: Long)(f: PartialFunction1[Message, a]): a -} -\end{verbatim} -The state of a message space consists of a multi-set of messages. -Messages are added to the space using the \verb@send@ method. Messages -are removed using the \verb@receive@ method, which is passed a message -processor \verb@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 \verb@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 \verb@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 \verb@TIMEOUT@ message. - -\appendix -\chapter{Scala Syntax Summary} - -The lexical syntax of Scala is given by the following grammar in EBNF -form. - -\begin{verbatim} - upper \=::= \=`A' | ... | `Z' | `$\Dollar$' | `_' - lower \>::= \>`a' | ... | `z' - letter \>::= \>upper | lower - digit \>::= \>`0' | ... | `9' - special \>::= \>``everything else except parentheses ([{}]) and period'' - - op \>::= \>special {special} [`_' [id]] - varid \>::= \>lower {letter | digit} [`_' [id]] - id \>::= \>upper {letter | digit} [`_' [id]] - \> |\>varid - \> |\>op - - intLit \>::= \>``as in Java'' - floatLit \>::= \>``as in Java'' - charLit \>::= \>``as in Java'' - stringLit \>::= \>``as in Java'' - - comment \>::= \>`/*' ``any sequence of characters'' `*/' - \> |\>`//' `any sequence of characters up to end of line'' -\end{verbatim} - -The context-free syntax of Scala is given by the following EBNF -grammar. - -\begin{verbatim} - literal \=::= \= intLit - \> |\> floatLit - \> |\> charLit - \> |\> stringLit - \> |\> symbolLit -\end{verbatim} - -\begin{verbatim} - 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 - \> |\> if `(' Expr `)' Expr [[`;'] else Expr] - \> |\> try `{' block `}' [catch Expr] [finally Expr] - \> |\> do Expr [`;'] while `(' Expr ')' - \> |\> for `(' Enumerators `)' (do | yield) Expr - \> |\> [SimpleExpr `.'] id `=' Expr - \> |\> SimpleExpr ArgumentExpr `=' Expr - \> |\> PostfixExpr [`:' Type1] - PostfixExpr \>::=\> InfixExpr [id] - InfixExpr \>::=\> PrefixExpr - \> |\> InfixExpr id InfixExpr - PrefixExpr \>::=\> [`-' | `+' | `~' | `!'] SimpleExpr - SimpleExpr \>::=\> literal - \> |\> true - \> |\> false - \> |\> null - \> |\> Path - \> |\> `(' [Expr] `)' - \> |\> BlockExpr - \> |\> new Template - \> |\> SimpleExpr `.' id - \> |\> id `#' id - \> |\> SimpleExpr TypeArgs - \> |\> SimpleExpr ArgumentExpr - ArgumentExpr \>::=\> `(' Expr ')' - \> |\> BlockExpr - BlockExpr \>::=\> `{' CaseClause {CaseClause} `}' - \> |\> `{' Block `}' - Block \>::=\> {BlockStat `;'} [Expr] -\end{verbatim} - -\begin{verbatim} - Enumerators \=::= \= Generator {`;' Enumerator} - Enumerator \>::=\> Generator - \> |\> Expr - Generator \>::=\> val Pattern `<-' Expr - Block \>::=\> {BlockStat `;'} [Expr] - BlockStat \>::=\> Import - \> |\> Def - \> |\> {LocalModifier} ClsDef - \> |\> Expr - \> |\> - - CaseClause \>::=\> case Pattern [`if' PostfixExpr] `=>' Block - - Constr \>::=\> StableId [TypeArgs] [`(' [Exprs] `)'] - - Pattern \>::= \= TreePattern { `|' TreePattern } - - TreePattern \>::= \> varid `:' Type - \> | \> `_' `:' Type - \> | \> SimplePattern [ '*' | '?' | '+' ] - \> | \> SimplePattern { id SimplePattern } - - SimplePattern \>::= \> varid [ '@' SimplePattern ] - \> | \> `_' - \> | \> 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}] `}' -\end{verbatim} -\begin{verbatim} - 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 ArgumentExpr - \> |\> `{' {BlockStat `;'} this ArgumentExpr {`;' BlockStat} `}' - - CompilationUnit \>::=\> [package QualId `;'] {TopStat `;'} TopStat - TopStat \>::=\> {Modifier} ClsDef - \> |\> Import - \> |\> Packaging - \> |\> - Packaging \>::=\> package QualId `{' {TopStat `;'} TopStat `}' - QualId \>::=\> id {`.' id} -\end{verbatim} - -case class extends { ... } - -trait List { } -class Nil -class Cons - -\comment{changes: - Type \=::= \= SimpleType {with SimpleType} [with Refinement] - \> |\> class SimpleType - SimpleType \>::=\> SimpleType [TypeArgs] - \> |\> `(' [Types] `)' - \> |\> - \> |\> this -} -\end{document} - -\comment{changes: - - Type \=::= \= SimpleType {with SimpleType} [with Refinement] - \> |\> class SimpleType - SimpleType \>::=\> TypeDesignator [TypeArgs] - \> |\> `(' Type `,' Types `)' - \> |\> `(' [Types] `)' Type - \> |\> this - - PureDef \>::=\> module ModuleDef {`,' ModuleDef} - \>::=\> def FunDef {`,' FunDef} - \> |\> type TypeDef {`,' TypeDef} - \> |\> [case] class ClassDef {`,' ClassDef} - \> |\> case CaseDef {`,' CaseDef} - CaseDef \>::=\> Ids ClassTemplate - - Modifier \>::=\> final - \> |\> private - \> |\> protected - \> |\> override [QualId] - \> |\> qualified - \> |\> abstract - -\section{Class Aliases} -\label{sec:class-alias} - -\syntax\begin{verbatim} - ClassDef \=::= \= ClassAlias - InterfaceDef \>::= \> ClassAlias - ClassAlias \>::= \> id [TypeParamClause] `=' SimpleType -\end{verbatim} - -Classes may also be defined to be aliases for other classes. A class -alias is of the form $\CLASS;c[tps] = d[targs]$ where $d[targs]$ is a -class type. Both $tps$ and $targs$ may be empty. -This introduces the type $c[tps]$ as an alias for type -$d[targs]$, in the same way the following type alias definition would: -\begin{verbatim} -type c[tps] = d[targs] -\end{verbatim} -The class alias definition is legal if the type alias definition would be legal. - -Assuming $d$ defines a class with type parameters $tps'$ and -parameters $(ps_1) \ldots (ps_n)$, the newly defined type is also -introduced as a class with a constructor which takes type parameters -$[tps]$, and which takes value parameters -$([targs/tps']ps_1)\ldots([targs/tps']ps_n)$. - -The modifiers \verb@private@ and -\verb@protected@ apply to a class alias independently of the class it represents. -The class $c$ is regarded as final if $d$ is final, or if a -\verb@final@ modifier is given for the alias definition. -$c$ is regarded as a case class iff $d$ is one. In this -case, -\begin{itemize} -\item the alias definition may also be prefixed with \verb@case@, and -\item the case constructor is also aliased, as if it was -defined such: -\begin{verbatim} -def c[tps](ps$_1$)\ldots(ps$_n$):D = d[targs]$([targs/tps']ps$_1$)\ldots([targs/tps']ps$_n$)$ . -\end{verbatim} -The new function $c$ is again classified as a case constructor, so -it may appear in constructor patterns (\sref{sec:patterns}). -\end{itemize} -Aliases for interfaces follow the same rules as class aliases, but -start with \verb@interface@ instead of \verb@class@. -} - -type T extends { ... } - -class C extends { ... } - -new C { ... } - -type C -class C < { ... } - -A & B & C & -\ifqualified{ -Parameter clauses (\sref{sec:funsigs}), -definitions that are local to a block (\sref{sec:blocks}), and import -clauses always introduce {\em simple names} $x$, which consist of a -single identifier. On the other hand, definitions and declarations -that form part of a module (\sref{sec:modules}) or a class -(\sref{sec:classes}) conceptually always introduce {\em qualified -names}\nyi{Qualified names are} -$Q\qex x$ where a simple name $x$ comes with a qualified -identifier $Q$. $Q$ is either the fully qualified name of a module or -class which is labelled -\verb@qualified@, or it is the empty name $\epsilon$. - -The {\em fully qualified name} of a module or class $M[targs]$ with -simple name $M$ and type arguments $[targs]$ is -\begin{itemize} -\item $Q.M$, if the definition of $M$ appears in the template defining -a module or class with fully qualified name $Q$. -\item -$M$ if the definition of $M$ appears on the top-level or as a definition -in a block. -\end{itemize} -} - -\ifqualified{ -It is possible that a definition in some class or module $M$ -introduces several qualified names $Q_1\qex x \commadots Q_n\qex x$ in a name -space that have the same simple name suffix but different qualifiers -$Q_1 \commadots Q_n$. This happens for instance if a module \verb@M@ -implements two qualified classes \verb@C@, \verb@D@ that each define a -function \verb@f@: -\begin{verbatim} -qualified abstract class B { def f: Unit = ""} -qualified abstract class C extends B { def f: Unit } -qualified abstract class D extends B { def f: Unit } - -module M extends C with D with { - override C def f = println("C::f") - override D def f = println("D::f") - \= - // f \>// error: ambiguous - (this:D).f \>// prints ``D::f'' -} - -def main() = (M:C).f \>// prints ``C::f'' -\end{verbatim} -Members of modules or classes are accessed using simple names, -not qualified names. - -The {\em qualified expansion} of a simple name $x$ in some type $T$ is -determined as follows: Let $Q_1\qex x \commadots Q_n\qex x$ be all the -qualified names of members of $T$ that have a simple name suffix $x$. -If one of the qualifiers $Q_i$ is the empty name $\epsilon$, then the -qualified expansion of $x$ in $T$ is $\epsilon\qex x$. Otherwise, let -$C_1 -\commadots C_n$ be the base classes (\sref{sec:base-classes}) -of $T$ that have fully qualified -names $Q_1 -\commadots Q_n$, respectively. If there exists a least class $C_j$ -among the $C_i$ in the subclass ordering, then the qualified expansion -of $x$ in $T$ is $Q_j\qex x$. Otherwise the qualified expansion does not -exist. - -Conversely, if $Q\qex x$ is the qualified expansion of some simple -name $x$ in $M$, we say that the entity named $Q\qex x$ in $M$ is {\em -identified in $M$ by the simple name} $x$. We leave out the -qualification ``in $M$'' if it is clear from the context. -In the example above, the qualified expansion of \verb@f@ in \verb@C@ -is \verb@C::f@, because \verb@C@ is a subclass of \verb@B@. On the -other hand, the qualified expansion of \verb@f@ in \verb@M@ does not -exist, since among the two choices \verb@C::f@ and \verb@D::f@ neither -class is a subclass of the other. - -A member access $e.x$ of some type term $e$ of type $T$ references the -member identified in $T$ by the simple name $x$ (i.e.\ the member -which is named by the qualified expansion of $x$ in $T$). - -In the example above, the simple name \verb@f@ in \verb@M@ would be -ambiguous since the qualified expansion of \verb@f@ in \verb@M@ does -not exist. To reference one of the two functions with simple name -\verb@f@, one can use an explicit typing. For instance, the name -\verb@(this:D).f@ references the implementation of \verb@D::f@ in -\verb@M@. -} - -\comment{ -\example The following example illustrates the difference between -virtual and non-virtual members with respect to overriding. - -\begin{verbatim} -class C with { - virtual def f = "f in C" - def g = "g in C" - def both1 = this.f ++ ", " ++ this.g - def both2 = f ++ ", " ++ g -} - -class D extends C with { - override def f = "f in D" - override def g = "redefined g in D" - new def g = "new g in D" -} - -val d = D -println(d.f) \=// prints ``f in D'' -println(d.g) \>// prints ``new g in D'' -println(d.both1) \>// prints ``f in D, redefined g in D'' -println(d.both2) \>// prints ``f in D, g in C'' - -val c: C = d -println(c.f) \=// prints ``f in D'' -println(c.g) \>// prints ``redefined g in D'' -println(c.both1) \>// prints ``f in D, redefined g in D'' -println(c.both2) \>// prints ``f in D, g in C'' -\end{verbatim} -} - -\comment{ -\section{The Self Type} -\label{sec:self-type} - -\syntax\begin{verbatim} -SimpleType \=::= \= $\This$ -\end{verbatim} - -The self type \verb@this@ may be used in the statement part of a -template, where it refers to the type of the object being defined by -the template. It is the type of the self reference \verb@this@. - -For every leaf class (\sref{sec:modifiers}) $C$, \verb@this@ is -treated as an alias for the class itself, as if it was declared such: -\begin{verbatim} -final class C ... with { - type this = C - ... -} -\end{verbatim} -For non-leaf classes $C$, \verb@this@ is treated as an abstract type -bounded by the class itself, as if it was declared such: -\begin{verbatim} -abstract class C ... with { - type this extends C - ... -} -\end{verbatim} - -Analogously, for every compound type \verb@$T_1$ with ... with $T_n$@, -\verb@this@ is treated as an abstract type conforming to the whole compound -type, as if it was bound in the refinement -\begin{verbatim} -type this extends $T_1$ with ... with $T_n$ . -\end{verbatim} -Finally, for every declaration of a parameter or abstract type -\mbox{$a \extends T$}, \verb@this@ is treated as an an abstract type -conforming to $a$, as if the bound type $T$ was augmented to -\verb@$T$ with { abstract type this extends $a$ }@. -On the other hand, if the parameter or abstract type is declared -\verb@final@, as in $\FINAL;a \extends T$, then \verb@this@ is treated as an alias -for $a$, as if the bound type $T$ was augmented to -\verb@$T$ with { type this = $a$ }@. - -\example -Consider the following classes for one- and two-dimensional -points with a \verb@distance@ method that computes the distance -between two points of the same type. -\begin{verbatim} -class Point1D(x: Float) with { - def xCoord = x - def distance (that: this) = abs(this.xCoord - that.xCoord) - def self: this = this -} -final class FinalPoint1D(x: Float) extends Point1D(x) - -class Point2D(x: Float, y: Float) extends Point1D(x) with { - def yCoord = y - override def distance(that: this) = - sqrt (square(this.xCoord - that.xCoord) + square(this.yCoord - that.yCoord)) -} -\end{verbatim} -Assume the following definitions: -\begin{verbatim} -val p1f: FinalPoint1D = FinalPoint1D(0.0) -val p1a: Point1D = p1f -val p1b: Point1D = Point2D(3.0, 4.0) -\end{verbatim} -Of the following expressions, three are well-formed, the other three -are ill-formed. -\begin{verbatim} -p1f distance p1f \=// OK, yields 0,0 -p1f distance p1b \>// OK, yields 3.0 -p1a distance p1a \>// OK, yields 0.0 -p1a distance p1f \>// ERROR, required: p1a.this, found: FinalPoint1D -p1a distance p1b \>// ERROR, required: p1a.this, found: p1b.this -p1b distance p1a \>// ERROR, required: p1b.this, found: p1a.this -\end{verbatim} -The last of these expressions would cause an illegal access to a -non-existing class \verb@yCoord@ of an object of type \verb@Point1D@, -if it were permitted to execute in spite of being not well-typed. -} - -\iflet{ -\section{Let Definitions} -\label{sec:letdef} - -\syntax\begin{verbatim} - PureDef \=::= \= $\LET$ ValDef {`,' ValDef} - ValDef \>::= \> id [`:' Type] `=' Expr -\end{verbatim} - -A let definition $\LET;x: T = e$ defines $x$ as a name of the value -that results from the delayed evaluation of $e$. The type $T$ must be -a concrete value type (\sref{sec:types}) and the type of the -expression $e$ must conform to $T$. The effect of the let definition -is to bind the left-hand side $x$ to the result of evaluating $e$ -converted to type $T$. However, the expression $e$ is not evaluated -at the point of the let definition, but is instead evaluated the first -time $x$ is dereferenced during execution of the program (which might -be never at all). An attempt to dereference $x$ again in the course of -evaluation of $e$ leads to a run-time error. Other threads trying to -dereference $x$ while $e$ is being evaluated block until evaluation is -complete. - -The type $T$ may be omitted if it can be determined using local type -inference (\sref{sec:local-type-inf}). -} - -\section{Packagings} - -\syntax\begin{verbatim} - Packaging \=::= \= package QualId `{' {TopStat `;'} TopStat `}' -\end{verbatim} - -A package is a special object which defines a set of member classes, -objects and packages. Unlike other objects, packages are not defined -by a definition. Instead, the set of members is determined by -packagings. - -A packaging \verb@package p { ds }@ injects all definitions in -\verb@ds@ as members into the package whose qualified name is -\verb@p@. If a definition in \verb@ds@ is labelled \verb@private@, it -is visible only for other members in the package. - -Selections \verb@p.m@ from \verb@p@ as well as imports from \verb@p@ -work as for objects. However, unlike other objects, packages may not -be used as values. It is illegal to have a package with the same fully -qualified name as an object or a class. - -Top-level definitions outside a packaging are assumed to be injected -into a special empty package. That package cannot be named and -therefore cannot be imported. However, members of the empty package -are visible to each other wihtout qualification. - -\example The following example will create a hello world program as -function \verb@main@ of module \verb@test.HelloWorld@. -\begin{verbatim} -package test; - -object HelloWord { - def main(args: Array[String]) = System.out.println("hello world") -} -\end{verbatim} - -\ifpackaging{ -Packagings augment top-level modules and classes. A simple packaging -$$\PACKAGE;id;\WITH;mi_1;\ldots;\WITH;mi_n;\WITH;(stats)$$ augments the -template of the top-level module or class named $id$ with new mixin -classes and with new member definitions. - -The static effect of such a packaging can be expressed as a -source-to-source tranformation which adds $mi_1 \commadots mi_n$ to -the mixin classes of $id$, and which adds the definitions in $stats$ -to the statement part of $id$'s template. Each type $mi_j$ must refer -to an interface type and $stats$ must consists only of pure and local -definitions. The augmented template and any class that extends it -must be well-formed. The aditional definitions may not overwrite -definitions of the augmented template, and they may not access private -members of it. - -Several packagings can be applied to the same top-level definition, -and those packagings may reside in different compilation units. - -A qualified packaging $\PACKAGE;Q.id;\WITH;t$ is equivalent to the -nested packagings -\begin{verbatim} -package $Q$ with { - package $id$ with $t$ -} -\end{verbatim} - -A packaging with type parameters $\PACKAGE;c[tps];\WITH;...$ applies to -a parameterized class $c$. The number of type parameters must equal -the number of type parameters of $c$, and every bound in $tps$ must -conform to the corresponding bound in the original definition of $c$. - -The augmented class has the type parameters given in its original -definition. If a parameter $a$ of an augmented class has a bound $T$ -which is a strict subtype of the corresponding bound in the original -class, $a \conforms T$ is taken as an {\em application condition} for -the packaging. That is, every time a member defined in the packaging -is accessed or a conformance between class $c$ and a mixin base class -of the packaging needs to be established, an (instantiation of) the -application condition is checked. An unvalidated application -condition constitutes a type error. \todo{Need to specify more -precisely when application conditions are checked} - -\example The following example will create a hello world program as -function \verb@main@ of module \verb@test.HelloWorld@. -\begin{verbatim} -package test with { - module HelloWord with { - def main(args: Array[String]) = out.println("hello world") - } -} -\end{verbatim} -This assumes there exists a top-level definition that defines a -\verb@test@ module, e.g.: -\begin{verbatim} -module test -\end{verbatim} - -\example The following packaging adds class \verb@Comparable@ -(\ref{ex:comparable}) as a mixin to class -\verb@scala.List@, provided the list elements are also comparable. -Every instance of \verb@List[$T$]@ will then implement -\verb@Comparable[List[$T$]]@ in the way it is defined in the -packaging. Each use of the added functionality for an instance type -\verb@List[$T$]@ requires that the application condition -\verb@T $<:$ Comparable@ is satisfied. -\begin{verbatim} -package scala.List[a extends Comparable[a]] with Comparable[List[a]] with { - def < (that: List[a]) = (this, that) match { - case (_, Nil) => False - case (Nil, _) => True - case (x :: xs, y :: ys) => (x < y) || (x == y && xs < ys) - } -} -\end{verbatim} -} -- cgit v1.2.3