ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 02.01.2026
Просмотров: 3452
Скачиваний: 0
Section 1.4 |
Chapter 1 · A Scalable Language |
65 |
useful documentation is what readers of a program cannot easily derive by themselves. In a method definition like:
def f(x: String) = ...
it’s useful to know that f’s argument should be a String. On the other hand, at least one of the two annotations in the following example is annoying:
val x: HashMap[Int, String] = new HashMap[Int, String]()
Clearly, it should be enough to say just once that x is a HashMap with Ints as keys and Strings as values; there’s no need to repeat the same phrase twice.
Scala has a very sophisticated type inference system that lets you omit almost all type information that’s usually considered annoying. In the previous example, the following two less annoying alternatives would work just as well:
val x = new HashMap[Int, String]()
val x: Map[Int, String] = new HashMap()
Type inference in Scala can go quite far. In fact, it’s not uncommon for user code to have no explicit types at all. Therefore, Scala programs often look a bit like programs written in a dynamically typed scripting language. This holds particularly for client application code, which glues together prewritten library components. It’s less true for the library components themselves, because these often employ fairly sophisticated types to allow flexible usage patterns. This is only natural. After all, the type signatures of the members that make up the interface of a reusable component should be explicitly given, because they constitute an essential part of the contract between the component and its clients.
1.4Scala’s roots
Scala’s design has been influenced by many programming languages and ideas in programming language research. In fact, only a few features of Scala are genuinely new; most have been already applied in some form in other languages. Scala’s innovations come primarily from how its constructs are put together. In this section, we list the main influences on Scala’s design. The list cannot be exhaustive—there are simply too many smart ideas around in programming language design to enumerate them all here.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Section 1.4 |
Chapter 1 · A Scalable Language |
66 |
At the surface level, Scala adopts a large part of the syntax of Java and C#, which in turn borrowed most of their syntactic conventions from C and C++. Expressions, statements, and blocks are mostly as in Java, as is the syntax of classes, packages and imports.15 Besides syntax, Scala adopts other elements of Java, such as its basic types, its class libraries, and its execution model.
Scala also owes much to other languages. Its uniform object model was pioneered by Smalltalk and taken up subsequently by Ruby. Its idea of universal nesting (almost every construct in Scala can be nested inside any other construct) is also present in Algol, Simula, and, more recently in Beta and gbeta. Its uniform access principle for method invocation and field selection comes from Eiffel. Its approach to functional programming is quite similar in spirit to the ML family of languages, which has SML, OCaml, and F# as prominent members. Many higher-order functions in Scala’s standard library are also present in ML or Haskell. Scala’s implicit parameters were motivated by Haskell’s type classes; they achieve analogous results in a more classical object-oriented setting. Scala’s actor-based concurrency library was heavily inspired by Erlang.
Scala is not the first language to emphasize scalability and extensibility. The historic root of extensible languages that can span different application areas is Peter Landin’s 1966 paper “The Next 700 Programming Languages.”16 (The language described in this paper, Iswim, stands beside Lisp as one of the pioneering functional languages.) The specific idea of treating an infix operator as a function can be traced back to Iswim and Smalltalk. Another important idea is to permit a function literal (or block) as a parameter, which enables libraries to define control structures. Again, this goes back to Iswim and Smalltalk. Smalltalk and Lisp both have a flexible syntax that has been applied extensively for building internal domain-specific languages. C++ is another scalable language that can be adapted and extended
15 The major deviation from Java concerns the syntax for type annotations—it’s “variable: Type” instead of “Type variable” in Java. Scala’s postfix type syntax resembles Pascal, Modula-2, or Eiffel. The main reason for this deviation has to do with type inference, which often lets you omit the type of a variable or the return type of a method. Using the “variable: Type” syntax this is easy—just leave out the colon and the type. But in C-style “Type variable” syntax you cannot simply leave off the type—there would be no marker to start the definition anymore. You’d need some alternative keyword to be a placeholder for a missing type (C# 3.0, which does some type inference, uses var for this purpose). Such an alternative keyword feels more ad-hoc and less regular than Scala’s approach.
16Landin, “The Next 700 Programming Languages.” [Lan66]
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Section 1.5 |
Chapter 1 · A Scalable Language |
67 |
through operator overloading and its template system; compared to Scala it is built on a lower-level, more systems-oriented core.
Scala is also not the first language to integrate functional and objectoriented programming, although it probably goes furthest in this direction. Other languages that have integrated some elements of functional programming into OOP include Ruby, Smalltalk, and Python. On the Java platform, Pizza, Nice, and Multi-Java have all extended a Java-like core with functional ideas. There are also primarily functional languages that have acquired an object system; examples are OCaml, F#, and PLT-Scheme.
Scala has also contributed some innovations to the field of programming languages. For instance, its abstract types provide a more object-oriented alternative to generic types, its traits allow for flexible component assembly, and its extractors provide a representation-independent way to do pattern matching. These innovations have been presented in papers at programming language conferences in recent years.17
1.5Conclusion
In this chapter, we gave you a glimpse of what Scala is and how it might help you in your programming. To be sure, Scala is not a silver bullet that will magically make you more productive. To advance, you will need to apply Scala artfully, and that will require some learning and practice. If you’re coming to Scala from Java, the most challenging aspects of learning Scala may involve Scala’s type system (which is richer than Java’s) and its support for functional programming. The goal of this book is to guide you gently up Scala’s learning curve, one step at a time. We think you’ll find it a rewarding intellectual experience that will expand your horizons and make you think differently about program design. Hopefully, you will also gain pleasure and inspiration from programming in Scala.
In the next chapter, we’ll get you started writing some Scala code.
17For more information, see [Ode03], [Ode05], and [Emi07] in the bibliography.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Chapter 2
First Steps in Scala
It’s time to write some Scala code. Before we start on the in-depth Scala tutorial, we put in two chapters that will give you the big picture of Scala, and most importantly, get you writing code. We encourage you to actually try out all the code examples presented in this chapter and the next as you go. The best way to start learning Scala is to program in it.
To run the examples in this chapter, you should have a standard Scala installation. To get one, go to http://www.scala-lang.org/downloads and follow the directions for your platform. You can also use a Scala plugin for Eclipse, IntelliJ, or NetBeans, but for the steps in this chapter, we’ll assume you’re using the Scala distribution from scala-lang.org.1
If you are a veteran programmer new to Scala, the next two chapters should give you enough understanding to enable you to start writing useful programs in Scala. If you are less experienced, some of the material may seem a bit mysterious to you. But don’t worry. To get you up to speed quickly, we had to leave out some details. Everything will be explained in a less “fire hose” fashion in later chapters. In addition, we inserted quite a few footnotes in these next two chapters to point you to later sections of the book where you’ll find more detailed explanations.
Step 1. Learn to use the Scala interpreter
The easiest way to get started with Scala is by using the Scala interpreter, an interactive “shell” for writing Scala expressions and programs. Simply type an expression into the interpreter and it will evaluate the expression and print
1We tested the examples in this book with Scala version 2.8.1.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Step 1 |
Chapter 2 · First Steps in Scala |
69 |
the resulting value. The interactive shell for Scala is simply called scala. You use it by typing scala at a command prompt:2
$ scala
Welcome to Scala version 2.8.1.
Type in expressions to have them evaluated. Type :help for more information.
scala>
After you type an expression, such as 1 + 2, and hit enter:
scala> 1 + 2
The interpreter will print:
res0: Int = 3
This line includes:
•an automatically generated or user-defined name to refer to the computed value (res0, which means result 0),
•a colon (:), followed by the type of the expression (Int),
•an equals sign (=),
•the value resulting from evaluating the expression (3).
The type Int names the class Int in the package scala. Packages in Scala are similar to packages in Java: they partition the global namespace and provide a mechanism for information hiding.3 Values of class Int correspond to Java’s int values. More generally, all of Java’s primitive types have corresponding classes in the scala package. For example, scala.Boolean corresponds to Java’s boolean. scala.Float corresponds to Java’s float. And when you compile your Scala code to Java bytecodes, the Scala compiler will use Java’s primitive types where possible to give you the performance benefits of the primitive types.
2If you’re using Windows, you’ll need to type the scala command into the “Command Prompt” DOS box.
3If you’re not familiar with Java packages, you can think of them as providing a full name for classes. Because Int is a member of package scala, “Int” is the class’s simple name, and “scala.Int” is its full name. The details of packages are explained in Chapter 13.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Step 2 |
Chapter 2 · First Steps in Scala |
70 |
The resX identifier may be used in later lines. For instance, since res0 was set to 3 previously, res0 * 3 will be 9:
scala> res0 * 3 res1: Int = 9
To print the necessary, but not sufficient, Hello, world! greeting, type:
scala> println("Hello, world!") Hello, world!
The println function prints the passed string to the standard output, similar to System.out.println in Java.
Step 2. Define some variables
Scala has two kinds of variables, vals and vars. A val is similar to a final variable in Java. Once initialized, a val can never be reassigned. A var, by contrast, is similar to a non-final variable in Java. A var can be reassigned throughout its lifetime. Here’s a val definition:
scala> val msg = "Hello, world!"
msg: java.lang.String = Hello, world!
This statement introduces msg as a name for the string "Hello, world!". The type of msg is java.lang.String, because Scala strings are implemented by Java’s String class.
If you’re used to declaring variables in Java, you’ll notice one striking difference here: neither java.lang.String nor String appear anywhere in the val definition. This example illustrates type inference, Scala’s ability to figure out types you leave off. In this case, because you initialized msg with a string literal, Scala inferred the type of msg to be String. When the Scala interpreter (or compiler) can infer types, it is often best to let it do so rather than fill the code with unnecessary, explicit type annotations. You can, however, specify a type explicitly if you wish, and sometimes you probably should. An explicit type annotation can both ensure the Scala compiler infers the type you intend, as well as serve as useful documentation for future readers of the code. In contrast to Java, where you specify a variable’s type before its name, in Scala you specify a variable’s type after its name, separated by a colon. For example:
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index
Step 2 |
Chapter 2 · First Steps in Scala |
71 |
scala> val msg2: java.lang.String = "Hello again, world!" msg2: java.lang.String = Hello again, world!
Or, since java.lang types are visible with their simple names4 in Scala programs, simply:
scala> val msg3: String = "Hello yet again, world!" msg3: String = Hello yet again, world!
Going back to the original msg, now that it is defined, you can use it as you’d expect, for example:
scala> println(msg) Hello, world!
What you can’t do with msg, given that it is a val, not a var, is reassign it.5 For example, see how the interpreter complains when you attempt the following:
scala> msg = "Goodbye cruel world!" <console>:6: error: reassignment to val
msg = "Goodbye cruel world!"
ˆ
If reassignment is what you want, you’ll need to use a var, as in:
scala> var greeting = "Hello, world!" greeting: java.lang.String = Hello, world!
Since greeting is a var not a val, you can reassign it later. If you are feeling grouchy later, for example, you could change your greeting to:
scala> greeting = "Leave me alone, world!" greeting: java.lang.String = Leave me alone, world!
To enter something into the interpreter that spans multiple lines, just keep typing after the first line. If the code you typed so far is not complete, the interpreter will respond with a vertical bar on the next line.
4The simple name of java.lang.String is String.
5In the interpreter, however, you can define a new val with a name that was already used before. This mechanism is explained in Section 7.7.
Cover · Overview · Contents · Discuss · Suggest · Glossary · Index