9780596155957
TypeLessDoMore.html

Chapter 2. Type Less, Do More

In This Chapter

We ended the last chapter with a few “teaser” examples of Scala code. This chapter discusses uses of Scala that promote succinct, flexible code. We’ll discuss organization of files and packages, importing other types, variable declarations, miscellaneous syntax conventions and a few other concepts. We’ll emphasize how the concise syntax of Scala helps you work better and faster.

Scala’s syntax is especially useful when writing scripts. Separate compile and run steps aren’t required for simple programs that have few dependencies on libraries outside of what Scala provides. You compile and run such programs in one shot with the scala command. If you’ve downloaded the example code for the book, many of the smaller examples can be run using the scala command, e.g., scala filename.scala. See the README.txt files in each chapter’s code examples for more details. See also the section called “Command Line Tools” in Chapter 14, Scala Tools, Libraries and IDE Support for more information about using the scala command.

Semicolons

You may have already noticed that there were very few semicolons in the code examples in the previous chapter. You can use semicolons to separate statements and expressions, as in Java, C, PHP, and similar languages. In most cases, though, Scala behaves like many scripting languages in treating the end of the line as the end of a statement or an expression. When a statement or expression is too long for one line, Scala can usually infer when you are continuing on to the next line, as shown in this example.

// code-examples/TypeLessDoMore/semicolon-example-script.scala

// Trailing equals sign indicates more code on next line
def equalsign = {
  val reallySuperLongValueNameThatGoesOnForeverSoYouNeedANewLine =
    "wow that was a long value name"

  println(reallySuperLongValueNameThatGoesOnForeverSoYouNeedANewLine)
}

// Trailing opening curly brace indicates more code on next line
def equalsign2(s: String) = {
  println("equalsign2: " + s)
}

// Trailing comma, operator, etc. indicates more code on next line
def commas(s1: String,
           s2: String) = {
  println("comma: " + s1 +
          ", " + s2)
}

When you want to put multiple statements or expressions on the same line, you can use semicolons to separate them. We used this technique in the ShapeDrawingActor example in the section called “A Taste of Concurrency” in Chapter 1, Zero to Sixty: Introducing Scala.

case "exit" => println("exiting..."); exit

This code could also be written as follows.

...
case "exit" =>
  println("exiting...")
  exit
...

You might wonder why you don’t need curly braces ({…}) around the two statements after the case … => line. You can put them in if you want, but the compiler knows when you’ve reached the end of the “block” when it finds the next case clause or the curly brace (}) that ends the enclosing block for all the case clauses.

Omitting optional semicolons means fewer characters to type and fewer characters to clutter your code. Breaking separate statements onto their own lines increases your code’s readability.

Variable Declarations

Scala allows you to decide whether a variable is immutable (read-only) or not (read-write) when you declare it. An immutable “variable” is declared with the keyword val (think value object).

val array: Array[String] = new Array(5)

To be more precise, the array reference cannot be changed to point to a different Array, but the array itself can be modified, as shown in the following scala session.

scala> val array: Array[String] = new Array(5)
array: Array[String] = Array(null, null, null, null, null)

scala> array = new Array(2)
<console>:5: error: reassignment to val
       array = new Array(2)
             ^

scala> array(0) = "Hello"

scala> array
res3: Array[String] = Array(Hello, null, null, null, null)

scala>

An immutable val must be initialized, that is defined, when it is declared.

A mutable variable is declared with the keyword var.

scala> var stockPrice: Double = 100.
stockPrice: Double = 100.0

scala> stockPrice = 10.
stockPrice: Double = 10.0

scala>

Scala also requires you to initialize a var when it is declared. You can assign a new value to a var as often as you want. Again, to be precise, the stockPrice reference can be changed to point to a different Double object (e.g., 10.). In this case, the object that stockPrice refers to can’t be changed, because Doubles in Scala are immutable.

There are a few exceptions to the rule that you must initialize val's and var's when they are declared. Both keywords can be used with constructor parameters. When used as constructor parameters, the mutable or immutable variables specified will be initialized when an object is instantiated. Both keywords can be used to declare "abstract" (uninitialized) variables in abstract types. Also, derived types can override vals declared inside parent types. We’ll discuss these exceptions in Chapter 5, Basic Object-Oriented Programming in Scala.

Scala encourages you to use immutable values whenever possible. As we will see, this promotes better object-oriented design and it is consistent with the principles of “pure” functional programming. It may take some getting used to, but you’ll find a newfound confidence in your code when it is written in an immutable style.

Note

The var and val keywords only specify if the reference can be changed to refer to a different object (var) or not (val). They don’t specify whether or not the object they reference is mutable.

Method Declarations

We saw several examples in Chapter 1, Zero to Sixty: Introducing Scala of how to define methods, which are functions that are members of a class. Method definitions start with the def keyword, followed by optional argument lists, a colon character ‘:’ and the return type of the method, an equals sign ‘=’, and finally the method body. Methods are implicitly declared “abstract” if you leave off the equals sign and method body. The enclosing type is then itself abstract. We’ll discuss abstract types in more detail in Chapter 5, Basic Object-Oriented Programming in Scala.

We said “optional argument lists”, meaning more than one. Scala lets you define more than one argument list for a method. This is required for currying methods, which we’ll discuss in the section called “Currying” in Chapter 8, Functional Programming in Scala. It is also very useful for defining your own domain-specific languages (DSLs), as we’ll see in Chapter 11, Domain-Specific Languages in Scala. Note that each argument list is surrounded by parentheses and the arguments are separated by commas.

If a method body has more than one expression, you must surround it with curly braces {…}. You can omit the braces if the method body has just one expression.

Method Default and Named Arguments (Scala Version 2.8)

Many languages let you define default values for some or all of the arguments to a method. Consider the following script with a StringUtil object that lets you join a list of strings with a user-specified separator.

// code-examples/TypeLessDoMore/string-util-v1-script.scala
// Version 1 of "StringUtil".

object StringUtil {
  def joiner(strings: List[String], separator: String): String =
    strings.mkString(separator)

  def joiner(strings: List[String]): String = joiner(strings, " ")
}
import StringUtil._  // Import the joiner methods.

println( joiner(List("Programming", "Scala")) )

There are actually two, “overloaded” joiner methods. The second one uses a single space as the “default” separator. Having two methods seems a bit wasteful. It would be nice if we could eliminate the second joiner method and declare that the separator argument in the first joiner has a default value. In fact, in Scala version 2.8, you can now do this.

// code-examples/TypeLessDoMore/string-util-v2-v28-script.scala
// Version 2 of "StringUtil" for Scala v2.8 only.

object StringUtil {
  def joiner(strings: List[String], separator: String = " "): String =
    strings.mkString(separator)
}
import StringUtil._  // Import the joiner methods.

println(joiner(List("Programming", "Scala")))

There is another alternative for earlier versions of Scala. You can use implicit arguments, which we will discuss in the section called “Implicit Function Parameters” in Chapter 8, Functional Programming in Scala.

Scala version 2.8 offers another enhancement for method argument lists, named arguments. We could actually write the last line of the previous example in several ways. All of the following println statements are functionally equivalent.

println(joiner(List("Programming", "Scala")))
println(joiner(strings = List("Programming", "Scala")))
println(joiner(List("Programming", "Scala"), " "))   // #1
println(joiner(List("Programming", "Scala"), separator = " ")) // #2
println(joiner(strings = List("Programming", "Scala"), separator = " "))

Why is this useful? First, if you choose good names for the method arguments, then your calls to those methods document each argument with a name. For example, compare the two lines with comments #1 and #2. In the first line, it may not be obvious what the second, " " argument is for. In the second case, we supply the name separator, which suggests the purpose of the argument.

The second benefit is that you can specify the parameters in any order when you specify them by name. Combined with default values, you can write code like the following

// code-examples/TypeLessDoMore/user-profile-v28-script.scala
// Scala v2.8 only.

object OptionalUserProfileInfo {
  val UnknownLocation = ""
  val UnknownAge = -1
  val UnknownWebSite = ""
}

class OptionalUserProfileInfo(
  location: String = OptionalUserProfileInfo.UnknownLocation,
  age: Int         = OptionalUserProfileInfo.UnknownAge,
  webSite: String  = OptionalUserProfileInfo.UnknownWebSite)

println( new OptionalUserProfileInfo )
println( new OptionalUserProfileInfo(age = 29) )
println( new OptionalUserProfileInfo(age = 29, location="Earth") )

OptionalUserProfileInfo represents all the “optional” user profile data in your next Web 2.0, social networking site. It defines default values for all its fields. The script creates instances with zero or more named parameters. The order of those parameters is arbitrary.

The examples we have shown use constant values as the defaults. Most languages with default argument values only allow constants or other values that can be determined at parse-time. However, in Scala, any expression can be used as the default, as long as it can compile where used. For example, an expression could not refer to an instance field that will be computed inside the class or object body, but it could invoke a method on a singleton object.

Finally, another constraint on named parameters is that once you provide a name for a parameter in a method invocation, then the rest of the parameters appearing after it must also be named. For example, new OptionalUserProfileInfo(age = 29, "Earth") would not compile because the second argument is not invoked by name.

We’ll see another useful example of named and default arguments when we discuss case classes in the section called “Case Classes” in Chapter 6, Advanced Object-Oriented Programming In Scala.

Nesting Method Definitions

Method definitions can also be nested. Here is an implementation of a factorial calculator, where we use a conventional technique of calling a second, nested method to do the work.

// code-examples/TypeLessDoMore/factorial-script.scala

def factorial(i: Int): Int = {
  def fact(i: Int, accumulator: Int): Int = {
    if (i <= 1)
      accumulator
    else
      fact(i - 1, i * accumulator)
  }

  fact(i, 1)
}

println( factorial(0) )
println( factorial(1) )
println( factorial(2) )
println( factorial(3) )
println( factorial(4) )
println( factorial(5) )

The second method calls itself recursively, passing an accumulator parameter, where the result of the calculation is “accumulated”. Note that we return the accumulated value when the counter i reaches 1. (We’re ignoring invalid negative integers. The function actually returns 1 for i < 0.) After the definition of the nested method, factorial calls it with the passed-in value i and the initial accumulator value of 1.

Like a local variable declaration in many languages, a nested method is only visible inside the enclosing method. If you try to call fact outside of factorial, you will get a compiler error.

Did you notice that we use i as a parameter name twice, first in the factorial method and again in the nested fact method? As in many languages, the use of i as a parameter name for fact “shadows” the outer use of i as a parameter name for factorial. This is fine, because we don’t need the outer value of i inside fact. We only use it the first time we call fact, at the end of factorial.

What if we need to use a variable that is defined outside a nested function. Consider this contrived example.

// code-examples/TypeLessDoMore/count-to-script.scala

def countTo(n: Int):Unit = {
  def count(i: Int): Unit = {
    if (i <= n) {
      println(i)
      count(i + 1)
    }
  }
  count(1)
}

countTo(5)

Note that the nested count method uses the n value that is passed as a parameter to countTo. There is no need to pass n as an argument to count. Because count is nested inside countTo, n is visible to it.

The declaration of a field (member variable) can be prefixed with keywords indicating the visibility, just as in languages like Java and C#. Similarly the declaration of a non-nested method can be prefixed with the same keywords. We will discuss the visibility rules and keywords in the section called “Visibility Rules” in Chapter 5, Basic Object-Oriented Programming in Scala.

Inferring Type Information

Statically-typed languages can be very verbose. Consider this typical declaration in Java.

import java.util.Map;
import java.util.HashMap;
...
Map<Integer, String> intToStringMap = new HashMap<Integer, String>();

We have to specify the type parameters <Integer, String> twice. (Scala uses the term type annotations for explicit type declarations like HashMap<Integer, String>.)

Scala supports type inference (see, for example, [TypeInference] and [Pierce2002]). The language’s compiler can discern quite a bit of type information from the context, without explicit type annotations. Here’s the same declaration rewritten in Scala, with inferred type information.

import java.util.Map
import java.util.HashMap
...
val intToStringMap: Map[Integer, String] = new HashMap

Recall from Chapter 1 that Scala uses square brackets ([…]) for generic type parameters. We specify Map[Integer, String] on the left-hand side of the equals sign. (We are sticking with Java types for the example.) On the right-hand side, we instantiate the actual type we want, a HashMap, but we don’t have to repeat the type parameters.

For completeness, suppose we don’t actually care if the instance is of type Map (the Java interface type). It can be of type HashMap for all we care.

import java.util.Map
import java.util.HashMap
...
val intToStringMap2 = new HashMap[Integer, String]

This declaration requires no type annotations on the left-hand side because all of the type information needed is on the right-hand side. The compiler automatically makes intToStringMap2 a HashMap[Integer,String].

Type inference is used for methods, too. In most cases, the return type of the method can be inferred, so the ‘:’ and return type can be omitted. However, type annotations are required for all method parameters.

Pure functional languages like Haskell (see, e.g., [O'Sullivan2009]) use type inference algorithms like Hindley-Milner (see [Spiewak2008] for an easily digested explanation). Code written in these languages require type annotations less often than in Scala, because Scala’s type inference algorithm has to support object-oriented typing as well as functional typing. So, Scala requires more type annotations than languages like Haskell. Here is a summary of the rules for when explicit type annotations are required in Scala.

Note

The Any type is the root of the Scala type hierarchy (see the section called “The Scala Type Hierarchy” in Chapter 7, The Scala Object System for more details). If a block of code returns a value of type Any unexpectedly, chances are good that the type inferencer couldn’t figure out what type to return, so it chose the most generic possible type.

Let’s look at examples where explicit declarations of method return types are required. In the following script, the upCase method has a conditional return statement for zero-length strings.

// code-examples/TypeLessDoMore/method-nested-return-script.scala
// ERROR: Won't compile until you put a String return type on upCase.

def upCase(s: String) = {
  if (s.length == 0)
    return s    // ERROR - forces return type of upCase to be declared.
  else
    s.toUpperCase()
}

println( upCase("") )
println( upCase("Hello") )

Running this script gives you the following error.

... 6: error: method upCase has return statement; needs result type
        return s
         ^

You can fix this error by changing the first line of the method to the following.

def upCase(s: String): String = {

Actually, for this particular script, an alternative fix is to remove the return keyword from the line. It is not needed for the code to work properly, but it illustrates our point.

Recursive methods also require an explicit return type. Recall our factorial method in the section called “Nesting Method Definitions”, previously in this chapter. Let’s remove the : Int return type on the nested fact method.

// code-examples/TypeLessDoMore/method-recursive-return-script.scala
// ERROR: Won't compile until you put an Int return type on "fact".

def factorial(i: Int) = {
  def fact(i: Int, accumulator: Int) = {
    if (i <= 1)
      accumulator
    else
      fact(i - 1, i * accumulator)  // ERROR
  }

  fact(i, 1)
}

Now it fails to compile.

... 9: error: recursive method fact needs result type
            fact(i - 1, i * accumulator)
             ^

Overloaded methods can sometimes require an explicit return type. When one such method calls another, we have to add a return type to the one doing the calling, as in this example.

// code-examples/TypeLessDoMore/method-overloaded-return-script.scala
// Version 1 of "StringUtil" (with a compilation error).
// ERROR: Won't compile: needs a String return type on the second "joiner".

object StringUtil {
  def joiner(strings: List[String], separator: String): String =
    strings.mkString(separator)

  def joiner(strings: List[String]) = joiner(strings, " ")   // ERROR
}
import StringUtil._  // Import the joiner methods.

println( joiner(List("Programming", "Scala")) )

The two joiner methods concatenate a List of strings together. The first method also takes an argument for the separator string. The second method calls the first with a “default” separator of a single space.

If you run this script, you get the following error.

... 9: error: overloaded method joiner needs result type
def joiner(strings: List[String]) = joiner(strings, "")

Since the second joiner method calls the first, it requires an explicit String return type. It should look like this.

  def joiner(strings: List[String]): String = joiner(strings, " ")

The final scenario can be subtle, when a more general return type is inferred than what you expected. You usually see this error when you assign a value returned from a function to a variable with a more specific type. For example, you were expecting a String, but the function inferred an Any for the returned object. Let’s see a contrived example that reflects a bug where this scenario can occur.

// code-examples/TypeLessDoMore/method-broad-inference-return-script.scala
// ERROR: Won't compile. Method actually returns List[Any], which is too "broad".

def makeList(strings: String*) = {
  if (strings.length == 0)
    List(0)  // #1
  else
    strings.toList
}

val list: List[String] = makeList()  // ERROR

Running this script returns the following error.

...11: error: type mismatch;
 found   : List[Any]
 required: List[String]
val list: List[String] = makeList()
                          ^

We intended for makeList to return a List[String], but when strings.length equals zero, we returned List(0), incorrectly “assuming” that this expression is the correct way to create an empty list. In fact, we returned a List[Int] with one element, 0. We should have returned List(). Since the else expression returns a List[String], the result of strings.toList, the inferred return type for the method is the closest common super type of List[Int] and List[String], which is List[Any]. Note that the compilation error doesn’t occur in the function definition. We only see it when we attempt to assign the value returned from makeList to a List[String] variable.

In this case, fixing the bug is the solution. Alternatively, when there isn’t a bug, it may be that the compiler just needs the “help” of an explicit return type declaration. Investigate the method that appears to return the unexpected type. In our experience, you often find that you modified that method (or another one in the call path) in such a way that the compiler now infers a more general return type than necessary. Add the explicit return type in this case.

Another way to prevent these problems is to always declare return types for methods, especially when defining methods for a public API. Let’s revisit our StringUtil example and see why explicit declarations are a good idea (adapted from [Smith2009a]).

Here is our StringUtil “API” again with a new method, toCollection.

// code-examples/TypeLessDoMore/string-util-v3.scala
// Version 3 of "StringUtil" (for all versions of Scala).

object StringUtil {
  def joiner(strings: List[String], separator: String): String =
    strings.mkString(separator)

  def joiner(strings: List[String]): String = strings.mkString(" ")

  def toCollection(string: String) = string.split(' ')
}

The toCollection method splits a string on spaces and returns an Array containing the substrings. The return type is inferred, which is a potential problem, as we will see. The method is somewhat contrived, but it will illustrate our point. Here is a client of StringUtil that uses this method.

// code-examples/TypeLessDoMore/string-util-client.scala

import StringUtil._

object StringUtilClient {
  def main(args: Array[String]) = {
    args foreach { s => toCollection(s).foreach { x => println(x) } }
  }
}

If you compile these files with scala, you can run the client as follows.

$ scala -cp ... StringUtilClient "Programming Scala"
Programming
Scala

Note

For the -cp … class path argument, use the directory where scalac wrote the class files, which defaults to the current directory (i.e., use -cp .). If you used the build process in the downloaded code examples, the class files are written to the build directory (using scalac -d build ...). In this case, use -cp build.

Everything is fine at this point, but now imagine that the code base has grown. StringUtil and its clients are now built separately and bundled into different jars. Imagine also that the maintainers of StringUtil decide to return a List instead of the default.

object StringUtil {
  ...

  def toCollection(string: String) = string.split(' ').toList  // changed!
}

The only difference is the final call to toList that converts the computed Array to a List. You recompile StringUtil and redeploy its jar. Then you run the same client, without recompiling it first.

$ scala -cp ... StringUtilClient "Programming Scala"
java.lang.NoSuchMethodError: StringUtil$.toCollection(...
  at StringUtilClient$$anonfun$main$1.apply(string-util-client.scala:6)
  at StringUtilClient$$anonfun$main$1.apply(string-util-client.scala:6)
...

What happened? When the client was compiled, StringUtil.toCollection returned an Array. Then toCollection was changed to return List. In both versions, the method return value was inferred. Therefore, client should have been recompiled, too.

However, had an explicit return type of Seq been declared, which is a parent for both Array and List, then the implementation change would not have forced a recompilation of the client.

Note

When developing APIs that are built separately from their clients, declare method return types explicitly and use the most general return type you can. This is especially important when APIs declare abstract methods (see, e.g., Chapter 4, Traits).

There is another scenario to watch for when using declarations of collections like val map = Map(), as in this example.

val map = Map()

map.update("book", "Programming Scala")
... 3: error: type mismatch;
 found   : java.lang.String("book")
 required: Nothing
map.update("book", "Programming Scala")
            ^

What happened? The type parameters of the generic type Map were inferred as [Nothing,Nothing] when the map was created. (We’ll discuss Nothing in the section called “The Scala Type Hierarchy” in Chapter 7, The Scala Object System, but its name is suggestive!) We attempted to insert an incompatible key, value pair of types String and String. Call it a Map to nowhere! The solution is to parameterize the initial map declaration, e.g., val map = Map[String, String]() or to specify initial values so the map parameters are inferred, e.g., val map = Map("Programming" → "Scala")

Finally, there is a subtle behavior with inferred return types that can cause unexpected and baffling results [ScalaTips]. Consider the following example scala session.

scala> def double(i: Int) { 2 * i }
double: (Int)Unit

scala> println(double(2))
()

Why did the second command print () instead of 4? Look carefully at what the scala interpreter said the first command returned, double (Int)Unit. We defined a method named double that takes an Int argument and returns Unit. The method doesn’t return an Int as we would expect.

The cause of this unexpected behavior is a missing equals sign in the method definition. Here is the definition we actually intended.

scala> def double(i: Int) = { 2 * i }
double: (Int)Int

scala> println(double(2))
4

Note the equals sign before the body of double. Now, the output says we have defined double to return an Int and the second command does what we expect it to do.

There is a reason for this behavior. Scala regards a method with the equals sign before the body as a function definition and a function always returns a value in functional programming. On the other hand, when Scala sees a method body without the leading equals sign, it assumes the programmer intended the method to be a “procedure” definition, intended for performing side effects only with the return value Unit. In practice, it is more likely that the programmer simply forget to insert the equals sign!

Warning

When the return type of a method is inferred and you don’t use an equals sign before the opening parenthesis for the method body, Scala infers a Unit return type, even when the last expression in the method is a value of another type.

By the way, where did that () come from that was printed before we fixed the bug? It is actually the real name of the singleton instance of the Unit type! (This name is a functional programming convention.)

Literals

Often, a new object is initialized with a literal value, such as val book = "Programming Scala". Let’s discuss the kinds of literal values supported by Scala. Here, we’ll limit ourselves to lexical syntax literals. We’ll cover literal syntax for functions (used as values, not member methods), tuples, and certain types like Lists and Maps, as we come to them.

Integer Literals

Integer literals can be expressed in decimal, hexadecimal, or octal. The details are summarized in Table 2.1, “Integer literals.”.

Table 2.1. Integer literals.

Kind Format Examples

Decimal

0 or a nonzero digit followed zero or more digits (0-9)

0, 1, 321

Hexadecimal

0x followed by one or more hexadecimal digits (0-9, A-F, a-f)

0xFF, 0x1a3b

Octal

0 followed by one or more octal digits (0-7)

013, 077


For Long literals, it is necessary to append the L or l character at the end of the literal. Otherwise, an Int is used. The valid values for an integer literal are bounded by the type of the variable to which the value will be assigned. Table 2.2, “Ranges of allowed values for integer literals (boundaries are inclusive).” defines the limits, which are inclusive.

Table 2.2. Ranges of allowed values for integer literals (boundaries are inclusive).

Target Type Minimum (inclusive) Maximum (inclusive)

Long

−263

263 - 1

Int

−231

231 - 1

Short

−215

215 - 1

Char

0

216 - 1

Byte

−27

27 - 1


A compile-time error occurs if an integer literal number is specified that is outside these ranges, as in the following examples.

scala > val i = 12345678901234567890
<console>:1: error: integer number too large
       val i = 12345678901234567890
scala> val b: Byte = 128
<console>:4: error: type mismatch;
 found   : Int(128)
 required: Byte
       val b: Byte = 128
                     ^

scala> val b: Byte = 127
b: Byte = 127

Floating Point Literals

Floating point literals are expressions with zero or more digits, followed by a period ., followed by zero or more digits. If there are no digits before the period, i.e., the number is less than 1.0, then there must be one or more digits after the period. For Float literals, append the F or f character at the end of the literal. Otherwise, a Double is assumed. You can optionally append a D or d for a Double.

Floating point literals can be expressed with or without exponentials. The format of the exponential part is e or E, followed by an optional + or -, followed by one or more digits.

Here are some example floating point literals.

0.
.0
0.0
3.
3.14
.14
0.14
3e5
3E5
3.E5
3.e5
3.e+5
3.e-5
3.14e-5
3.14e-5f
3.14e-5F
3.14e-5d
3.14e-5D

Float consists of all IEEE 754 32-bit, single-precision binary floating point values. Double consists of all IEEE 754 64-bit, double-precision binary floating point values.

Warning

To avoid parsing ambiguities, you must have at least one space after a floating point literal, if it is followed by a token that starts with a letter. Also, the expression 1.toString returns the integer value 1 as a string, while 1. toString uses the operator notation to invoke toString on the floating point literal 1..

Boolean Literals

The boolean literals are true and false. The type of the variable to which they are assigned will be inferred to be Boolean.

scala> val b1 = true
b1: Boolean = true

scala> val b2 = false
b2: Boolean = false

Character Literals

A character literal is either a printable Unicode character or an escape sequence, written between single quotes. A character with Unicode value between 0 and 255 may also be represented by an octal escape, a backslash \ followed by a sequence of up to three octal characters. It is a compile time error if a backslash character in a character or string literal does not start a valid escape sequence.

Here are some examples.

’A’
’\u0041’  // 'A' in Unicode
’\n’
'\012'    // '\n' in octal
’\t’

The valid escape sequences are shown in Table 2.3, “Character escape sequences.”.

Table 2.3. Character escape sequences.

Sequence Unicode Meaning

\b

\u0008

backspace BS

\t

\u0009

horizontal tab HT

\n

\u000a

linefeed LF

\f

\u000c

form feed FF

\r

\u000d

carriage return CR

\"

\u0022

double quote "

\’

\u0027

single quote

\\

\u0009

backslash \


String Literals

A string literal is a sequence of characters enclosed in double quotes or triples of double quotes, i.e., """…""".

For string literals in double quotes, the allowed characters are the same as the character literals. However, if a double quote " character appears in the string, it must be “escaped” with a \ character. Here are some examples.

"Programming\nScala"
"He exclaimed, \"Scala is great!\""
"First\tSecond"

The string literals bounded by triples of double quotes are also called multi-line string literals. These strings can cover several lines; the line feeds will be part of the string. They can include any characters, including one or two double quotes together, but not three together. They are useful for strings with \ characters that don’t form valid Unicode or escape sequences, like the valid sequences listed in Table 2.3, “Character escape sequences.”. Regular expressions are a typical example, which we’ll discuss in Chapter 3, Rounding Out the Essentials. However, if escape sequences appear, they aren’t interpreted.

Here are three example strings.

"""Programming\nScala"""
"""He exclaimed, "Scala is great!" """
"""First line\n
Second line\t

Fourth line"""

Note that we had to add a space before the trailing """ in the second example to prevent a parse error. Trying to escape the second " that ends the "Scala is great!" quote, i.e., "Scala is great!\", doesn’t work.

Copy and paste these strings into the scala interpreter. Do the same for the previous string examples. How are they interpreted differently?

Symbol Literals

Scala supports symbols, which are interned strings, meaning that two symbols with the same “name”, i.e., the same character sequence, will actually refer to the same object in memory. Symbols are used less often in Scala than in some other languages, like Ruby, Smalltalk, and Lisp. They are useful as map keys instead of strings.

A symbol literal is a single quote ', followed by a letter, followed by zero or more digits and letters. Note that an expression like '1 is invalid, because the compiler thinks it is an incomplete character literal.

A symbol literal ’id is a shorthand for the expression scala.Symbol("id").

Note

If you want to create a symbol that contains whitespace, use e.g., scala.Symbol(" Programming Scala "). All the whitespace is preserved.

Tuples

How many times have you wanted to return two or more values from a method? In many languages, like Java, you only have a few options, none of which is very appealing. You could pass in parameters to the method that will be modified for all or some of the “return” values, which is ugly. Or, you could declare some small “structural” class that holds the two or more values, then return an instance of that class.

Scala, supports tuples, a grouping of two or more items, usually created with the literal syntax of a comma-separated list of the items inside parentheses, e.g., (x1, x2, …). The types of the xi elements are unrelated to each other, you can mix and match types. These literal “groupings” are instantiated as scala.TupleN instances, where the N is the number of items in the tuple. The Scala API defines separate TupleN classes for N between 1 and 22, inclusive. Tuple instances are immutable, first-class values, so you can assign them to variables, pass them as values, and return them from methods.

The following example demonstrates the use of tuples.

// code-examples/TypeLessDoMore/tuple-example-script.scala

def tupleator(x1: Any, x2: Any, x3: Any) = (x1, x2, x3)

val t = tupleator("Hello", 1, 2.3)
println( "Print the whole tuple: " + t )
println( "Print the first item:  " + t._1 )
println( "Print the second item: " + t._2 )
println( "Print the third item:  " + t._3 )

val (t1, t2, t3) = tupleator("World", '!', 0x22)
println( t1 + " " + t2 + " " + t3 )

Running this script with scala produces the following output.

Print the whole tuple: (Hello,1,2.3)
Print the first item:  Hello
Print the second item: 1
Print the third item:  2.3
World ! 34

The tupleator method simply returns a “3-tuple” with the input arguments. The first statement that uses this method assigns the returned tuple to a single variable t. The next four statements print t in various ways. The first print statement calls Tuple3.toString, which wraps parentheses around the item list. The following three statements print each item in t separately. The expression t._N retrieves the N item, starting at 1, not 0 (this choice follows functional programming conventions).

The last two lines show that we can use a tuple expression on the left-hand side of the assignment. We declare three vals, t1, t2, and t3, to hold the individual items in the tuple. In essence, the tuple items are extracted automatically.

Notice how we mixed types in the tuples. You can see the types more clearly if you use the interactive mode of the scala command, which we introduced in Chapter 1, Zero to Sixty: Introducing Scala.

Invoke the scala command with no script argument. At the scala> prompt, enter val t = ("Hello",1,2.3) and see that you get the following result, which shows you the types of each element in the tuple.

scala> val t = ("Hello",1,2.3)
t: (java.lang.String, Int, Double) = (Hello,1,2.3)

It’s worth noting that there’s more than one way to define a tuple. We’ve been using the more common parenthesized syntax, but you can also use the arrow operator between two values, as well as special factory methods on the tuple-related classes.

scala> 1 -> 2
res0: (Int, Int) = (1,2)

scala> Tuple2(1, 2)
res1: (Int, Int) = (1,2)

scala> Pair(1, 2)
res2: (Int, Int) = (1,2)

Option, Some, and None: Avoiding nulls

We’ll discuss the standard type hierarchy for Scala in the section called “The Scala Type Hierarchy” in Chapter 7, The Scala Object System. However, three useful classes to understand now are the Option class and its two subclasses, Some and None.

Most languages have a special keyword or object that’s assigned to reference variables when there’s nothing else for them to refer to. In Java, this is null; in Ruby, it’s nil. In Java, null is a keyword, not an object, and thus it’s illegal to call any methods on it. But this is a confusing choice on the language designer’s part. Why return a keyword when the programmer expects an object?

To be more consistent with the goal of making everything an object, as well as to conform with functional programming conventions, Scala encourages you to use the Option type for variables and function return values when they may or may not refer to a value. When there is no value, use None, an object that is a subclass of Option. When there is a value, use Some, which wraps the value. Some is also a subclass of Option.

Note

None is declared as an object, not a class, because we really only need one instance of it. In that sense, it’s like the null keyword, but it is a real object with methods.

You can see Option, Some, and None in action in the following example, where we create a map of state capitals in the United States.

// code-examples/TypeLessDoMore/state-capitals-subset-script.scala

val stateCapitals = Map(
  "Alabama" -> "Montgomery",
  "Alaska"  -> "Juneau",
  // ...
  "Wyoming" -> "Cheyenne")

println( "Get the capitals wrapped in Options:" )
println( "Alabama: " + stateCapitals.get("Alabama") )
println( "Wyoming: " + stateCapitals.get("Wyoming") )
println( "Unknown: " + stateCapitals.get("Unknown") )

println( "Get the capitals themselves out of the Options:" )
println( "Alabama: " + stateCapitals.get("Alabama").get )
println( "Wyoming: " + stateCapitals.get("Wyoming").getOrElse("Oops!") )
println( "Unknown: " + stateCapitals.get("Unknown").getOrElse("Oops2!") )

The convenient -> syntax for defining name-value pairs to initialize a Map will be discussed in the section called “The Predef Object” in Chapter 7, The Scala Object System. For now, we want to focus on the two groups of println statements, where we show what happens when you retrieve the values from the map. If you run this script with the scala command, you’ll get the following output.

Get the capitals wrapped in Options:
Alabama: Some(Montgomery)
Wyoming: Some(Cheyenne)
Unknown: None
Get the capitals themselves out of the Options:
Alabama: Montgomery
Wyoming: Cheyenne
Unknown: Oops2!

The first group of println statements invoke toString implicitly on the instances returned by get. We are calling toString on Some or None instances, because the values returned by Map.get are automatically wrapped in a Some, when there is a value in the map for the specified key. Note that the Scala library doesn’t store the Some in the map, it wraps the value in a Some upon retrieval. Conversely, when we ask for a map entry that doesn’t exist, the None object is returned, rather than null. This occurred in the last println of the three.

The second group of println statements go a step further. After calling Map.get, they call get or getOrElse on each Option instance to retrieve the value it contains. Option.get requires that the Option is not empty, that is, the Option instance must actually be a Some. In this case, get returns the value wrapped by the Some, as demonstrated in the println where we print the capital of Alabama. However, if the Option is actually None, then None.get throws a NoSuchElementException.

We also show the alternative method, getOrElse, in the last two println statements. This method returns either the value in the Option, if it is a Some instance, or it returns the second argument we passed to getOrElse, if it is a None instance. In other words, the second argument to getOrElse functions as the default return value.

So, getOrElse is the more defensive of the two methods. It avoids a potential thrown exception. We’ll discuss the merits of alternatives like get vs. getOrElse in the section called “Exceptions and the Alternatives” in Chapter 13, Application Design.

Note that because the Map.get method returns an Option, it automatically documents the fact that there may not be an item matching the specified key. The map handles this situation by returning a None. Most languages would return null (or the equivalent) when there is no “real” value to return. You learn from experience to expect a possible null. Using Option makes the behavior more explicit in the method signature, so it’s more self-documenting.

Also, thanks to Scala’s static typing, you can’t make the mistake of attempting to call a method on a value that might actually be null. While this mistake is easy to do in Java, it won’t compile in Scala because you must first extract the value from the Option. So, the use of Option strongly encourages more resilient programming.

Because Scala runs on the JVM and .NET and because it must interoperate with other libraries, Scala has to support null. Still, you should avoid using null in your code. Tony Hoare, who invented the null reference in 1965 while working on an object-oriented language called ALGOL W, called its invention his “billion dollar mistake” [Hoare2009]. Don’t contribute to that figure.

So, how would you write a method that returns an Option? Here is a possible implementation of get that could be used by a concrete subclass of of Map (Map.get itself is abstract). For a more sophisticated version, see the implementation of get in scala.collection.immutable.HashMap in the Scala library source code distribution.

def get(key: A): Option[B] = {
  if (contains(key))
    new Some(getValue(key))
  else
    None
}

The contains method is also defined for Map. It returns true if the map contains a value for the specified key. The getValue method is intended to be an internal method that retrieves the value from the underlying storage, whatever it is.

Note how the value returned by getValue is wrapped in a Some[B], where the type B is inferred. However, if the call to contains(key) returns false, then the object None is returned.

You can use this same idiom when your methods return an Option. We’ll explore other uses for Option in subsequent sections. Its pervasive use in Scala code makes it an important concept to grasp.

Organizing Code in Files and Namespaces

Scala adopts the package concept that Java uses for namespaces, but Scala offers a more flexible syntax. Just as file names don’t have to match the type names, the package structure does not have to match the directory structure. So, you can define packages in files independent of their “physical” location.

The following example defines a class MyClass in a package com.example.mypkg using the conventional Java syntax.

// code-examples/TypeLessDoMore/package-example1.scala

package com.example.mypkg

class MyClass {
  // ...
}

The next example shows a contrived example that defines packages using the nested package syntax in Scala, which is similar to the namespace syntax in C# and the use of modules as namespaces in Ruby.

// code-examples/TypeLessDoMore/package-example2.scala

package com {
  package example {
    package pkg1 {
      class Class11 {
        def m = "m11"
      }
      class Class12 {
        def m = "m12"
      }
    }

    package pkg2 {
      class Class21 {
        def m = "m21"
        def makeClass11 = {
          new pkg1.Class11
        }
        def makeClass12 = {
          new pkg1.Class12
        }
      }
    }

    package pkg3.pkg31.pkg311 {
      class Class311 {
        def m = "m21"
      }
    }
  }
}

Two packages pkg1 and pkg2 are defined under the com.example package. A total of three classes are defined between the two packages. The makeClass11 and makeClass12 methods in Class21 illustrate how to reference a type in the “sibling” package, pkg1. You can also reference these classes by their full paths, com.example.pkg1.Class11 and com.example.pkg1.Class12, respectively.

The package pkg3.pkg31.pkg311 shows that you can “chain” several packages together in one clause. It is not necessary to use a separate package clause for each package.

Following the conventions of Java, the root package for Scala’s library classes is named scala.

Warning

Scala does not allow package declarations in scripts that are executed directly with the scala interpreter. The reason has to do with the way the interpreter converts statements in scripts to valid Scala code before compiling to byte code. See the the section called “The scala Command Line Tool” section in Chapter 14, Scala Tools, Libraries and IDE Support for more details.

Importing Types and Their Members

To use declarations in packages, you have to import them, just as you do in Java and similarly for other languages. However, compared to Java, Scala greatly expands your options. The following example illustrates several ways to import Java types.

// code-examples/TypeLessDoMore/import-example1.scala

import java.awt._
import java.io.File
import java.io.File._
import java.util.{Map, HashMap}

You can import all types in a package, using the underscore _ as a wild card, as shown on the first line. You can also import individual Scala or Java types, as shown on the second line.

Java uses the “star” character * as the wild card for matching all types in a package or all static members of a type when doing “static imports”. In Scala, this character is allowed in method names, so _ is used as a wild card, as we saw previously.

As shown on the third line, you can import all the static methods and fields in Java types. If java.io.File were actually a Scala object, as discussed previously, then this line would import the fields and methods from the object.

Finally, you can selectively import just the types you care about. On the fourth line, we import just the java.util.Map and java.util.HashMap types from the java.util package. Compare this one-line import statement with the two-line import statements we used in our first example in the section called “Inferring Type Information”. They are functionally equivalent.

The next example shows more advanced options for import statements.

// code-examples/TypeLessDoMore/import-example2-script.scala

def writeAboutBigInteger() = {

  import java.math.BigInteger.{
    ONE => _,
    TEN,
    ZERO => JAVAZERO }

  // ONE is effectively undefined
  // println( "ONE: "+ONE )
  println( "TEN: "+TEN )
  println( "ZERO: "+JAVAZERO )
}

writeAboutBigInteger()

This example demonstrates two features. First, we can put import statements almost anywhere we want, not just at the top of the file, as required by Java. This feature allows us to scope the imports more narrowly. For example, we can’t reference the imported BigInteger definitions outside the scope of the method. Another advantage of this feature is that it puts an import statement closer to where the imported items are actually used.

The second feature shown is the ability to rename imported items. First, the java.math.BigInteger.ONE constant is renamed to the underscore wild card. This effectively makes it invisible and unavailable to the importing scope. This is a useful technique when you want to import everything except a few particular items.

Next, the java.math.BigInteger.TEN constant is imported without renaming, so it can be referenced simply as TEN.

Finally, the java.math.BigInteger.ZERO constant is given the alias JAVAZERO.

Aliasing is useful if you want to give the item a more convenient name or you want to avoid ambiguities with other items in scope that have the same name.

Imports are Relative

There’s one other important thing to know about imports; they are relative. Note the comments for the following imports:

// code-examples/TypeLessDoMore/relative-imports.scala

import scala.collection.mutable._
import collection.immutable._         // Since "scala" is already imported
import _root_.scala.collection.jcl._  // full path from real "root"

package scala.actors {
  import remote._                     // We're in the scope of "scala.actors"
}

Note that the last import statement nested in the scala.actor package scope is relative to that scope.

The [ScalaWiki] has other examples at http://scala.sygneca.com/faqs/language#how-do-i-import.

It’s fairly rare that you’ll have problems with relative imports, but the problem with this convention is that they sometimes cause surprises, especially if you are accustomed to languages like Java, where imports are absolute. If you get a mystifying compiler error that a package wasn’t found, check that the statement is properly relative to the last the import statement or add the _root_. prefix. Also, you might see an IDE or other tool insert an import _root_… statement in your code. Now you know what it means.

Warning

Remember that import statements are relative, not absolute. To create an absolute path, start with _root_.

Abstract Types And Parameterized Types

We mentioned in the section called “A Taste of Scala” in Chapter 1, Zero to Sixty: Introducing Scala that Scala supports parameterized types, which are very similar to generics in Java. (We could use the two terms interchangeably, but it’s more common to use “parameterized types” in the Scala community and “generics” in the Java community.) The most obvious difference is in the syntax, where Scala uses square brackets ([…]), while Java uses angle brackets (<…>).

For example, a list of strings would be declared as follows.

val languages: List[String] = ...

There are other important differences with Java’s generics, which we’ll explore in the section called “Understanding Parameterized Types” in Chapter 12, The Scala Type System.

For now, we’ll mention one other useful detail that you’ll encounter before we can explain it in depth in Chapter 12, The Scala Type System. If you look at the declaration of scala.List in the Scaladocs, you’ll see that the declaration is written as … class List[+A]. The ‘+’ in front of the A means that List[B] is a subtype of List[A] for any B that is a subtype of A. If there is a ‘-’ in front of a type parameter, then the relationship goes the other way, Foo[B] would be a supertype of Foo[A], if the declaration is Foo[-A].

Scala supports another type abstraction mechanism called abstract types, used in many functional programming languages, such as Haskell. Abstract types were also considered for inclusion in Java when generics were adopted. We want to introduce them now, because you’ll see many examples of them before we dive into their details in Chapter 12, The Scala Type System. For a very detailed comparison of these two mechanisms, see [Bruce1998].

Abstract types can be applied to many of the same design problems for which parameterized types are used. However, while the two mechanisms overlap, they are not redundant. Each has strengths and weaknesses for certain design problems.

Here is an example that uses an abstract type.

// code-examples/TypeLessDoMore/abstract-types-script.scala

import java.io._

abstract class BulkReader {
  type In
  val source: In
  def read: String
}

class StringBulkReader(val source: String) extends BulkReader {
  type In = String
  def read = source
}

class FileBulkReader(val source: File) extends BulkReader {
  type In = File
  def read = {
    val in = new BufferedInputStream(new FileInputStream(source))
    val numBytes = in.available()
    val bytes = new Array[Byte](numBytes)
    in.read(bytes, 0, numBytes)
    new String(bytes)
  }
}

println( new StringBulkReader("Hello Scala!").read )
println( new FileBulkReader(new File("abstract-types-script.scala")).read )

Running this script with scala produces the following output.

Hello Scala!
import java.io._

abstract class BulkReader {
...

The BulkReader abstract class declares three abstract members, a type named In, a val field source, and a read method. As in Java, instances in Scala can only be created from concrete classes, which must have definitions for all members.

The derived classes, StringBulkReader and FileBulkReader, provide concrete definitions for these abstract members. We’ll cover the details of class declarations in Chapter 5, Basic Object-Oriented Programming in Scala and the particulars of overriding member declarations in the section called “Overriding Members of Classes and Traits” in Chapter 6, Advanced Object-Oriented Programming In Scala.

For now, note that the type field works very much like a type parameter in a parameterized type. In fact, we could rewrite this example as follows, where we show only what would be different.

abstract class BulkReader[In] {
  val source: In
  ...
}

class StringBulkReader(val source: String) extends BulkReader[String] {...}

class FileBulkReader(val source: File) extends BulkReader[File] {...}

Just as for parameterized types, if we define the In type to be String, then the source field must also be defined as a String. Note that the StringBulkReader's read method simply returns the source field, while the FileBulkReader's read method reads the contents of the file.

As demonstrated by [Bruce1998], parameterized types tend to be best for collections, which is how they are most often used in Java code, while abstract types are most useful for type “families” and other type scenarios.

We’ll explore the details of Scala’s abstract types in Chapter 12, The Scala Type System. For example, we’ll see how to constrain the possible concrete types that can be used.

Reserved Words

Table 2.4, “Reserved Words.” lists the reserved words in Scala, which we sometimes call “keywords”, and briefly describes how they are used [ScalaSpec2009].

Table 2.4. Reserved Words.

Word Description See …

abstract

Makes a declaration abstract. Unlike Java, the keyword is usually not required for abstract members.

the section called “Class and Object Basics”, (Chapter 5, Basic Object-Oriented Programming in Scala)

case

Start a case clause in a match expression.

the section called “Pattern Matching” (Chapter 3, Rounding Out the Essentials)

catch

Start a clause for catching thrown exceptions.

the section called “Using try, catch, and finally Clauses” (Chapter 3, Rounding Out the Essentials)

class

Start a class declaration.

the section called “Class and Object Basics” (Chapter 5, Basic Object-Oriented Programming in Scala)

def

Start a method declaration.

the section called “Method Declarations” (Chapter 2, Type Less, Do More)

do

Start a do … while loop.

the section called “Other Looping Constructs” (Chapter 3, Rounding Out the Essentials)

else

Start an else clause for an if clause.

the section called “Scala if Statements” (Chapter 3, Rounding Out the Essentials)

extends

Indicates that the class or trait that follows is the parent type of the class or trait being declared.

the section called “Parent Classes” (Chapter 5, Basic Object-Oriented Programming in Scala)

false

Boolean false.

the section called “The Scala Type Hierarchy” (Chapter 7, The Scala Object System)

final

Applied to a class or trait to prohibit deriving child types from it. Applied to a member to prohibit overriding it in a derived class or trait.

the section called “Attempting to Override final Declarations” (Chapter 6, Advanced Object-Oriented Programming In Scala)

finally

Start a clause that is executed after the corresponding try clause, whether or not an exception is thrown by the try clause.

the section called “Using try, catch, and finally Clauses” (Chapter 3, Rounding Out the Essentials)

for

Start a for comprehension (loop).

the section called “Scala for Comprehensions” (Chapter 3, Rounding Out the Essentials)

forSome

Used in existential type declarations to constrain the allowed concrete types that can be used.

the section called “Existential Types” (Chapter 12, The Scala Type System)

if

Start an if clause.

the section called “Scala if Statements” (Chapter 3, Rounding Out the Essentials)

implicit

Marks a method as eligible to be used as an implicit type converter. Marks a method parameter as optional, as long as a type-compatible substitute object is in the scope where the method is called.

the section called “Implicit Conversions” (Chapter 8, Functional Programming in Scala)

import

Import one or more types or members of types into the current scope.

the section called “Importing Types and Their Members” (this chapter)

lazy

Defer evaluation of a val.

the section called “Lazy Vals” (Chapter 8, Functional Programming in Scala)

match

Start a pattern matching clause.

the section called “Pattern Matching” (Chapter 3, Rounding Out the Essentials)

new

Create a new instance of a class.

the section called “Class and Object Basics” (Chapter 5, Basic Object-Oriented Programming in Scala)

null

Value of a reference variable that has not been assigned a value.

the section called “The Scala Type Hierarchy” (Chapter 7, The Scala Object System)

object

Start a singleton declaration; a class with only one instance.

the section called “Classes and Objects: Where Are the Statics?” (Chapter 5, Basic Object-Oriented Programming in Scala)

override

Override a concrete member of a class or trait, as long as the original is not marked final.

the section called “Overriding Members of Classes and Traits” (Chapter 6, Advanced Object-Oriented Programming In Scala)

package

Start a package scope declaration.

the section called “Organizing Code in Files and Namespaces” (Chapter 2, Type Less, Do More)

private

Restrict visibility of a declaration.

the section called “Visibility Rules” (Chapter 5, Basic Object-Oriented Programming in Scala)

protected

Restrict visibility of a declaration.

the section called “Visibility Rules” (Chapter 5, Basic Object-Oriented Programming in Scala)

requires

Deprecated. Was used for self typing.

the section called “The Scala Type Hierarchy” (Chapter 7, The Scala Object System)

return

Return from a function

the section called “A Taste of Scala” (Chapter 1, Zero to Sixty: Introducing Scala)

sealed

Applied to a parent class to require all directly derived classes to be declared in the same source file.

the section called “Case Classes” (Chapter 6, Advanced Object-Oriented Programming In Scala)

super

Analogous to this, but binds to the parent type.

the section called “Overriding Abstract and Concrete Methods” (Chapter 6, Advanced Object-Oriented Programming In Scala)

this

How an object refers to itself. The method name for auxiliary constructors.

the section called “Class and Object Basics” (Chapter 5, Basic Object-Oriented Programming in Scala)

throw

Throw an exception.

the section called “Using try, catch, and finally Clauses” (Chapter 3, Rounding Out the Essentials)

trait

A mixin module that adds additional state and behavior to an instance of a class

Chapter 4, Traits

try

Start a block that may throw an exception.

the section called “Using try, catch, and finally Clauses” (Chapter 3, Rounding Out the Essentials)

true

Boolean true.

the section called “The Scala Type Hierarchy” (Chapter 7, The Scala Object System)

type

Start a type declaration

the section called “Abstract Types And Parameterized Types” (Chapter 2, Type Less, Do More)

val

Start a read-only “variable” declaration.

the section called “Variable Declarations” (Chapter 2, Type Less, Do More)

var

Start a read/write variable declaration.

the section called “Variable Declarations” (Chapter 2, Type Less, Do More)

while

Start a while loop.

the section called “Other Looping Constructs” (Chapter 3, Rounding Out the Essentials)

with

Include the trait that follows in the class being declared or the object being instantiated.

Chapter 4, Traits

yield

Return an element in a for comprehension that becomes part of a sequence.

the section called “Yielding” (Chapter 3, Rounding Out the Essentials)

_

A place holder, used in imports, function literals, etc.

Many

:

Separator between identifiers and type annotations.

the section called “A Taste of Scala” (Chapter 1, Zero to Sixty: Introducing Scala)

=

Assignment

the section called “A Taste of Scala” (Chapter 1, Zero to Sixty: Introducing Scala)

=>

Used in function literals to separate the argument list from the function body.

the section called “Function Literals and Closures” (Chapter 8, Functional Programming in Scala)

<-

Used in for comprehensions in generator expressions.

the section called “Scala for Comprehensions” (Chapter 3, Rounding Out the Essentials)

<:

Used in parameterized and abstract type declarations to constrain the allowed types.

the section called “Type Bounds” (Chapter 12, The Scala Type System)

<%

Used in parameterized and abstract type “view bounds” declarations.

the section called “Type Bounds” (Chapter 12, The Scala Type System)

>:

Used in parameterized and abstract type declarations to constrain the allowed types.

the section called “Type Bounds” (Chapter 12, The Scala Type System)

#

Used in type projections

the section called “Type Projections” (Chapter 12, The Scala Type System)

@

Marks an annotation

the section called “Annotations” (Chapter 13, Application Design)

(Unicode \u21D2) same as =>.

the section called “Function Literals and Closures” (Chapter 8, Functional Programming in Scala)

(Unicode \u2190) same as <-.

the section called “Scala for Comprehensions” (Chapter 3, Rounding Out the Essentials)


Notice that break and continue are not listed. These control keywords don’t exist in Scala. Instead, Scala encourages you to use functional programming idioms that are usually more succinct and less error prone. We’ll discuss alternative approaches when we discuss for loops (see the section called “Generator Expressions” in Chapter 3, Rounding Out the Essentials).

Some Java methods use names that are reserved by Scala, e.g., java.util.Scanner.match. To avoid a compilation error, surround the name with single back quotes, e.g., java.util.Scanner.‵match‵.

Recap and What’s Next

We covered several ways that Scala’s syntax is concise, flexible, and productive. We also described many Scala features. In the next chapter, we will round out some Scala essentials before we dive into Scala’s support for object-oriented programming and functional programming.

Site last updated on: April 15, 2011 at 06:39:28 AM PDT
Cover for Programming Scala

View 3 comments

  1. Leonidas – Posted May 24, 2009

    So, the recommendation for Scala code is to leave the semicolons out, right? I'm asking because semicolons are can be included or left out in both Python and JavaScript, but in Python it is considered a bad habit to put them in and in JavaScript, it is good style to finish the statements with semicolons.

    I want to write idiomatic Scala-code from day one, so it would be good to know a recommendation in this regard.

  2. deanwampler – Posted June 3, 2009

    We didn't say it explicitly, but yes, anything optional tends to get left out ;) I'm not sure why the JS community prefers to have the semicolons after statements.

  3. yingliu97 – Posted March 6, 2011

    test

Add a comment

View 2 comments

  1. parthm – Posted July 6, 2009

    Is there a style recommendation on using or not using braces with case that can be put in here? The preferred approach by the scala community.

  2. deanwampler – Posted July 9, 2009

    Most people leave them out when they can. Will consider adding more verbage about that.

Add a comment

View 4 comments

  1. reidhoch – Posted May 20, 2009

    type inferencer just doesn't sound right, perhaps it should be "Type inference can figure this one out easily."

  2. Leonidas – Posted May 24, 2009

    val only means that a variable cannot be re-assigned, therefore val a = new Array[Int](3) is still a mutable variable. I think the paragraph above should explain that it is the name that cannot be reassigned, not that the object bound to it becomes read-only in some magic way.

  3. deanwampler – Posted June 3, 2009

    @Reid, I think the most recent drafts use "inference" (my bad...)

    @Marek. Yes, it should be more clear. I'll fix.

  4. derekmahar – Posted July 9, 2009

    @Marek: I think the variable is actually immutable. The variable is the reference cell which refers to the object and the name is the identifier assigned to this cell. I agree with you that the name associated with the variable never changes (though you can create aliases using other references), so the name is immutable. I also agree with you that the object to which the variable refers is mutable. However, I disagree that the variable contents, which is a reference to the object and not the object itself is mutable. The "val" keyword applies to the variable, not to the name or the object.

Add a comment

View 3 comments

  1. TimMacEachern – Posted June 23, 2009

    Perhaps it would be better to say: "In this case, the value inherent in the object that stockPrice refers to can't be changed...".

  2. derekmahar – Posted July 9, 2009

    ...or explain briefly why Doubles are immutable.

  3. deanwampler – Posted July 12, 2009

    Adding "in Scala" -> "... Doubles in Scala are immutable." Not a complete explanation, but a reasonable change at this late date and it implies that Doubles are immutable by design in Scala.

Add a comment

View 7 comments

  1. bfollek – Posted June 19, 2009

    In the Notes that follows:

    "the referred to object is mutability" should be "the object referred to is mutable"

  2. deanwampler – Posted Sept. 1, 2009

    Thanks. Fixed.

  3. prashanthvvbabu – Posted Sept. 3, 2009

    "They don’t specify whether or not the object they reference is mutability."

    Its not yet fixed.

  4. TheMattrix – Posted Sept. 3, 2009

    While you're at it, I believe it should be:

    "They don’t specify whether or not the object which they reference is mutable."

  5. robertkuhar – Posted Sept. 11, 2009

    The 2nd sentence in the "Note" box has a grammar problem. I think it should read "They don't specify whether or not the object they reference is mutable".

  6. DaveP – Posted Sept. 16, 2009

    They don’t specify whether or not the object they reference is mutability.

    Suggest 'mutable' rather than mutability

  7. myang – Posted July 14, 2010

    So can I say an object consists only of a bunch of references? When change an object, it's actually to re-assign the reference to another object. And how to make an object read-only?

Add a comment

View 12 comments

  1. retronym – Posted June 10, 2009

    'followed by an optional argument list in parenthesese' should be qualified with a footnote that refers to a later section showing methods with multiple argument lists and currying.

  2. deanwampler – Posted June 10, 2009

    Will fix.

  3. jamison – Posted Sept. 11, 2009

    They don’t specify whether or not the object they reference is mutability.

    Should be "reference is mutable" or "reference's mutability".

  4. DaveP – Posted Sept. 16, 2009

    start with the def keyword, followed by optional argument lists

    Oops. You've forgotten the method name?

    start with the def keyword, followed by the method name, followed by optional argument lists

  5. Iassan – Posted June 26, 2010

    I believe, that after def keyword should be method name rather than argument list.

  6. myang – Posted July 14, 2010

    Is this similar to method overloading?

  7. chapter_29 – Posted Aug. 3, 2010

    "The enclosing type is then itself abstract."

    This sentence suggest that the abstract keyword is also optional for classes, what would be a bad idea in my opinion, because you were forced to scan a whole class to find out if it is possibly impicitly abstract. But i tried it out and it is not allowed. The code piece ...

    class Foo { def bar(): Unit }

    ... produces, fortunately: "error: class Foo needs to be abstract, since method bar is not defined".

  8. chapter_29 – Posted Aug. 3, 2010

    "The enclosing type is then itself abstract."

    This sentence suggest that the keyword "abstract" is optional for classes, too. First that would have been an really bad idea by the designer, because you as reader were forced to scan each class completly to be sure that it is not implicitly abstract.

    But I tried it and this piece of code ...

    class Foo { def bar(): Unit }

    produces fortunately: "error: class Foo needs to be abstract, since method bar is not defined"

  9. ajasmin – Posted Aug. 24, 2010

    Shouldn't the method name follow the def keyword?

  10. nikoapos – Posted Sept. 25, 2010

    The def keyword is followed by the name of the method, which is followed by the argument lists.

  11. bruno – Posted Dec. 28, 2010

    Method definitions start with the def keyword, followed by [the method name, ] optional argument lists...

  12. ddekany – Posted Jan. 3, 2011

    According to the Scala Style Guide, the = in a method definition should be omitted if the method returns Unit (i.e., void), and this has a good reason. In this book, when the return type meant to be Unit, you tend to use = and then let Scala infer the return type, and that's a horrible combination, as that way the return type will be whatever the return type of the last statement happens to be. Then not only you can accidentally change the type of the method during maintenance, but also it's hard to see what the return type is, despite that's a very important information. It's not nit-picking... Scala syntax is easy to abuse, so unless we want to hurt the reputation of Scala with a lot of hard-to-read source code, it's important to hammer the possible best style into the head of beginners, and this book is for them.

Add a comment

View 2 comments

  1. bfollek – Posted June 19, 2009

    "each argument is" => "each argument list is"

  2. deanwampler – Posted July 12, 2009

    Will fix.

Add a comment

View 2 comments

  1. battisti – Posted May 24, 2009

    Shouldn't it be "has more than one expression" instead of "more than one statement"? According to the Scala Reference: "Both declarations and definitions produce bindings that associate type names with type definitions or bounds..." to associate something with something, you'd need an expression (i.e. something, that returns a value with a type to bind against) and not a statement which "just does something"

  2. deanwampler – Posted June 3, 2009

    Yes, ti should be expression. Thanks.

Add a comment

View 1 comment

  1. weixian – Posted Oct. 9, 2009

    Why is it required to wrap the joiner() function inside an object? I tried to define the 2 copies of joiner outside of the object, and I got error "error: wrong number of arguments for method joiner: (List[String])String".

Add a comment

View 4 comments

  1. maddalab – Posted July 26, 2009

    Example should include

    StringUtils.joiner(separator="|", strings=List("Programming", "Scala"))

    with named argument one could avoid positional arguments entirely

  2. maddalab – Posted July 26, 2009

    Dope, Spoke to soon, Sorry about that

  3. belun – Posted Jan. 27, 2011

    this is a nice way to avoid magic numbers or to avoid forcing the programmer to create named variables just to express what some value means

  4. a s – Posted Jan. 3, 2012

    What happens when you mix positional and named parameters, like example #2? Here it's easy, but if you have several parameters of the same type?

Add a comment

View 3 comments

  1. mheld – Posted May 8, 2010

    Doesn't the OptionalUserProfileInfo need a toString method? Otherwise you'll get something like:

    Main$$anon$1$OptionalUserProfileInfo@491c4c Main$$anon$1$OptionalUserProfileInfo@1e0f2f6 Main$$anon$1$OptionalUserProfileInfo@16f25a7

  2. mheld – Posted May 8, 2010

    Doesn't this code need a toString method? this outputs something like:

    Main$$anon$1$OptionalUserProfileInfo@491c4c Main$$anon$1$OptionalUserProfileInfo@1e0f2f6 Main$$anon$1$OptionalUserProfileInfo@16f25a7

  3. nikoapos – Posted Sept. 25, 2010

    It would be nice if the class OptionalUserProfileInfo was overriding the toString method, so the different values in which the parameters are initialized will be visible on the println calls.

Add a comment

View 9 comments

  1. parthm – Posted July 6, 2009
    personalWebSite: String = OptionalUserProfileInfo.UnknownWebSite)
    

    instead of? personalWebSite = OptionalUserProfileInfo.UnknownWebSite)

    Haven't tried this on the scala 2.8 shell.

  2. deanwampler – Posted July 12, 2009

    Thanks. We caught and fixed that one.

  3. jonhanson – Posted Aug. 16, 2009

    This code sample appears to be using constructs we haven't been introduced to yet. What is a "case class" and how can this one have the same name as the object defined a few lines above?

  4. deanwampler – Posted Aug. 22, 2009

    Will remove the word "case", which isn't necessary here. Sorry

  5. phill – Posted Sept. 19, 2009

    The above example with the series of println is only useful if the there is // the following println examples are too useful without an override of toString override def toString(): String = { getClass.getSimpleName + "{ location = " + location + " age = " + age + " webSite = " + webSite + " }"; }

    Then running the example three printlns results in something interesting.

  6. phill – Posted Sept. 19, 2009
    // the println examples in the above example are only useful with an override of toString
    override def toString(): String = {
      getClass.getSimpleName + "{ location = " + location + " age = " + age + " webSite = " + webSite + " }";
    }
    
  7. toolbear74 – Posted Dec. 25, 2009

    next Web 2.0, social networking site

    Too snarky, not amusing enough.

  8. palik – Posted May 28, 2010

    add toString method in OptionalUserProfileInfo class { override def toString() = "UserProfileInfo(location:" + location + ", age: " + age + ", webSite: " + webSite +")" }

  9. buptwhisper – Posted Oct. 25, 2010

    add the name with the value of the parameter, the order is not that important yet.

Add a comment

View 1 comment

  1. ymnk – Posted Oct. 8, 2009

    The sentence "For example, an expression could not refer to an instance field that will be computed inside the class or object body, but it could invoke a method on a singleton object." is not clear. Especially, the meaning of "an expression could not refer to an instance field that will be computed inside object body" is not clear. An explicit example as a code will be helpful.

Add a comment

View 5 comments

  1. magle – Posted May 26, 2009

    The nested method declares the same parameter name 'i' as the surrounding method, thus shadowing the parameter of the surrounding method. I'm not sure if this is done in full purpose here, since you're otherwise able to refer to the parameterlist of the surrounding method within the body of the nested method. May be better to use a different parameter name for the nested method even for the sake of clarity.

  2. deanwampler – Posted June 4, 2009

    Good point. Expanded this section to discuss it.

  3. GatesDA – Posted July 9, 2009

    "The function actually return 1" => "The function actually returns 1" "the accumulator value of 1" => "an initial accumulator value of 1"

  4. deanwampler – Posted July 12, 2009

    Will fix these. Thanks.

  5. stubs – Posted Feb. 26, 2010

    The function actually returns 1 for i <= 0.

    Readers should not be confused about this silly version of factorial choosen to to show nested method definitions.

    The traditional version used to explain recursion in many places would be:

    def factorial(i: Int): Int = { if (i <= 1) 1 else i * factorial(i - 1) }

    Perhaps an example without a pointless recursion would do a better job here.

Add a comment

View 1 comment

  1. imho – Posted Dec. 2, 2010

    It would be more logical to take first the case of a reference to a variable in an outer scope that is not shadowed, and then the shadowed case.

Add a comment

View 1 comment

  1. toolbear74 – Posted Dec. 25, 2009

    Worth pointing out that, unlike in Java, you don't have to declare n as final.

Add a comment

View 1 comment

  1. debio264 – Posted Dec. 28, 2009

    This paragraph seems... out of place. It's connected to the current topic, but you need to make it clear that it does change the subject slightly. Maybe I'm just slow, but it took me a minute to change gears from nested functions and closures to OOP visibility.

Add a comment

View 1 comment

  1. scooter libby – Posted April 29, 2013

    In Java 5 you can use the diamond operator to omit the second .

Add a comment

View 2 comments

  1. zefhemel – Posted May 20, 2009

    Actually it's the language's compiler that can discern quite a bit of type information.

  2. deanwampler – Posted June 4, 2009

    We've been using the term parser, but yes, it's the compiler. Plan to fix.

Add a comment

View 6 comments

  1. parthm – Posted June 1, 2009

    On the first line we specify Map[Int, String]

    You probably mean Map[Integer, String] above.

  2. deanwampler – Posted June 4, 2009

    Thanks. will fix.

  3. TimMacEachern – Posted June 23, 2009

    So now the reader is wondering: "Why's he using Int in one place and Integer in another?"

  4. deanwampler – Posted July 9, 2009

    @Tim, fair point. I was sticking with Java types, since that's how I started out in this bit. Should say as much

  5. wyuenho – Posted March 20, 2010

    Here is a good time to tell people why () can be omitted.

  6. wyuenho – Posted March 20, 2010

    Here would be a good time to tell people why () are omitted.

Add a comment

View 1 comment

  1. imho – Posted Dec. 2, 2010

    "suppose we don’t actually care if the instance is of type Map" Should you not have said: "suppose we don’t actually care if the variable 'intToStringMap' is declared as type Map" Because " the instance is of type Map " is true in all cases

Add a comment

View 5 comments

  1. clojure – Posted May 21, 2009

    "are not as mature" sounds like there's hope for a lot of improvement, which is not at all that clear to me.

  2. deanwampler – Posted June 7, 2009

    Rewording

  3. jrimmer – Posted Aug. 26, 2009

    "... less often than in Scala, because Scala’s type inference ...", extraneous comma and "So, Scala requires more type annotations than languages like Haskell." Redundant sentence though if felt necessary suggest rewording casual 'So, .." with 'Thus' or 'Therefore'. "Here is a summary ... required in Scala.", This is also redundant considering the following breakout section title.

  4. charlesporter – Posted Sept. 21, 2009

    // As in these examples, the equals sign after the method signature seems to be // necessary to avoid an implicit type of Unit

    def implicitString(in: String) = { in }

    def implicitUnit(in: String) { in }

    val v = "implicit return" val y = "no implicit return"

    // prints "implicit return" println(implicitString(v))

    // prints "()" println(implicitUnit(y))

  5. imho – Posted Dec. 2, 2010

    Below in "Note", you write " If a block of code returns a value of type Any unexpectedly..." This sounds like you are talking about runtime type, but you mean the compile-time type inferred by the compiler. For example,

    object Fiddle { def faddle(flag: Boolean) = { if (flag) true else 55 } } and then scala> Fiddle.faddle(false) res18: AnyVal = 55

    but the "AnyVal" is only the compiler talking; the value returned is an int and the runtime knows that:

    scala> Fiddle.faddle(false).isInstanceOf[Int] res17: Boolean = true

    So the "value returned" is not "unexpectedly of type AnyVal" any more than any other Int, e.g. val foo : Int = 7.

Add a comment

View 4 comments

  1. retronym – Posted May 20, 2009

    3.d When the method is an implicit method that the compiler will automatically use to convert from one type to another.

  2. deanwampler – Posted June 4, 2009

    Actually, you aren't required to declare the return type. for example, implicit def int2String(i:Int) = i.toString works fine. However, it's actually a good idea to add the return type annotation anyway to avoid some potential subtle bugs when the method is refined over time.

  3. idleneuron – Posted April 14, 2010

    After reading all the exceptions I would personally not use Type Inference feature. I like explicit types as it adds programmer's intention and improves readability (faster to understand especially scrolling down the code).

    I'm not yet convinced by 'Type Inference' sales pitch of Scala and others (F#).

  4. myang – Posted July 14, 2010

    why does an explicit return require a type annotation?

Add a comment

View 3 comments

  1. parthm – Posted June 1, 2009

    In the printlns, upper should be upCase

  2. deanwampler – Posted June 4, 2009

    Doh! Thanks.

  3. NikolajLindberg – Posted Oct. 19, 2009

    Tiny comment: I'm probably missing something, but I fail to see the beauty of this example.

    This doesn't look like a proper "if-then-else" situation, since "" == "".toUpperCase (that is, it's fine to call toUpperCase on the empty string, which mean you don't need the "else").

    In other words, one would expect the method to be def upCase(s: String) = s.toUpperCase, which is pretty meaningless :-)

    (It would be a different story if you, e.g., checked for null, and returned "".)

Add a comment

View 3 comments

  1. diathesis – Posted June 23, 2009

    Seems like a discussion as to why a return requires type annotation would be useful.

  2. deanwampler – Posted Sept. 1, 2009

    We couldn't add a discussion of this before going to the printer. I don't know the full details, but it's a limitation of the type inferencing engine. Perhaps it can be fixed in a future version, but I don't know.

  3. buptwhisper – Posted Oct. 25, 2010

    but sometimes, we should just add return statement, so the method's return type surely needed.

Add a comment

View 1 comment

  1. xezz744 – Posted April 11, 2010

    Why the caller? If the return type of the callEE was specified, the return type of the caller could be inferred (in this example anyway).

Add a comment

View 3 comments

  1. myee – Posted July 11, 2009

    The code listing (method-overloaded-return-script.scala) seems out of sync with the text: (1) the second joiner is taking a list of strings (2) the first joiner doesn't have a default value for separator (which doesn't match the "def joiner(strings: String*) = joiner(strings.toList)" below

  2. deanwampler – Posted July 12, 2009

    Doh. You're right. I changed the example and didn't update the text. Will fix. Thanks.

  3. phill – Posted Sept. 19, 2009

    This last sentence seems redundant since the example is taken from earlier in THIS chapter.

Add a comment

View 4 comments

  1. maddalab – Posted July 26, 2009

    Some where along the way you went from a method that has an argument of List[String] to a method that has an var age String*

    Code def joiner(strings: List[String]) = joiner(strings, " ")

    Compiler Errors def joiner(strings: String*) = joiner(strings.toList)

  2. deanwampler – Posted Aug. 22, 2009

    Yep. Will fix.

  3. po6eynj02 – Posted Oct. 10, 2009

    Learning Scala for the first time with this on-line book. Some of these rules for when explicit typing are needed make some sense. But others are confusing for me. For instance, I understand why recursion causes a problem. But why method overloading? If I change the name of the function to something else, then everything compiles fine. This seems really counterintuitive to me because I feel there's nothing special about method overloading to impeded type inference.

    So there's a couple of things that are possible. I might be overlooking something that's key to understand. Or the implementation of the Scala interpretter is just idiosyncratic (and later versions might fix things). Either way, I'd certainly appreciate any comments you can add to help make these rules make sense. For instance, when generics were put into Java a lot of books were nice enough to explain how type erasure related to the odd rules.

  4. ldeck – Posted Oct. 18, 2009

    Yep (Sukant) - the rule I've learnt from this page => always use a return type. But otherwise no return type necessary if the method is self-contained and doesn't use the return keyword.

    I think there's too much discussion on the differences leading to confusion. It'd be better pushed to an appendix -- but the aim was to sell the less typing mantra. Looks to me like this is a problem with the interpreter.

Add a comment

View 4 comments

  1. robcd – Posted June 20, 2009

    Did you copy-and-paste the previous example, by any chance?

  2. deanwampler – Posted July 12, 2009

    Thanks. changed the example, but not the text. Doh!

  3. derekmahar – Posted Aug. 5, 2009

    You also forgot to change the comment text. It still refers to the "joiner" example above.

  4. deanwampler – Posted Aug. 22, 2009

    @Derek. Yep, will fix. Thanks.

Add a comment

View 2 comments

  1. Marius – Posted July 9, 2009

    The sentence "We intended for makeList to return a List[String], but the case 0 expression actually returns a List[Int]" mentions a "case 0" which does not exist, the example above contains an if-clause. Seems to me as if the example has changed. I would propose to use the comment "#1" in the example (which isn't referred to for any reason) and write instead "We intended for makeList to return a List[String], but the if-clause marked with "#1" actually returns a List[Int]".

  2. deanwampler – Posted July 12, 2009

    Thanks. See my previous comment reply...

Add a comment

View 2 comments

  1. TimMacEachern – Posted June 23, 2009

    You didn't have a StringUtil example, you had a NameUtil example.

  2. deanwampler – Posted July 12, 2009

    Fixed.

Add a comment

View 4 comments

  1. parthm – Posted June 1, 2009

    As Lists haven't been discussed in some detail at this point, 'head :: tail' pattern matching and Nil usage in the above example may be difficult to understand for someone who doesn't know about it already. Maybe a short note on that can be added.

    Also, is addition numbers to code listings (Listing. N) planned?

  2. parthm – Posted June 1, 2009

    It would be good to mention that the (string).r notation used above is the regex notation and creates a scala.util.matching.Regex

  3. deanwampler – Posted June 4, 2009

    I'm considering a different example that doesn't require these features that haven't been discussed yet. Concerning numbers and labels, we already do that with some of the larger examples. We are evaluating the balance between too many labeled examples and too few.

  4. deanwampler – Posted June 4, 2009

    I came up with a much simpler example.

Add a comment

View 1 comment

  1. Martin_Suesskraut – Posted June 9, 2009

    Shouldn't the comma between "scala" and "collection" be a dot?

Add a comment

View 1 comment

  1. ralphrmartin – Posted April 20, 2010

    (1) seems like new is missing here (2) even with new, I get :11: error: trait Map is abstract; cannot be instantiated

Add a comment

View 5 comments

  1. Ragnvald – Posted Sept. 26, 2009

    Arrow symbol should be -> (dash gt), not → (arrow)

  2. debio264 – Posted Dec. 28, 2009

    Did some sort of autoformatter give you the arrow in that last bit of code? I don't think that's Scala syntax...

  3. peterf – Posted Jan. 16, 2010

    val map = Map( etc... This is an example line of code. What is the special "->" symbol in the Map()? Do I type this special symbol in when I'm programming scala?

  4. evilek – Posted Dec. 15, 2010

    I think there should be:

    val map = new HashMap()

    and later on aswell as you can't instantiate Map interface.

  5. jprupp – Posted Nov. 1, 2011

    Unicode character → can replace sequence -> in Scala. Both are valid.

Add a comment

View 4 comments

  1. battisti – Posted May 25, 2009

    Wouldn't be "square" a more appropriate method name? Or def double(i: Int) = { 2 * i }

  2. deanwampler – Posted June 7, 2009

    Bug. will fix. Thanks!

  3. jwolski – Posted July 11, 2009

    Isn't it more common to make the comparison of Unit to Void?

  4. deanwampler – Posted July 12, 2009

    Right, absent minded typing... changing to void.

Add a comment

View 2 comments

  1. magle – Posted May 29, 2009

    You may could mention the reason way methods without an equals sign always leads to return type Unit: Methods offering an equals sign are considered as functions which always return a value when called. Methods without an equals sign are considered as procedures which (only) produce some side effects. That said, those methods don't return any value and hence offer a return type Unit.

  2. deanwampler – Posted June 7, 2009

    Good point. Will add a paragraph for it.

Add a comment

View 1 comment

  1. abucchi – Posted Feb. 10, 2010

    s/forget/forgot in "... more likely that the programmer simply forget to insert the equals sign!"

Add a comment

View 1 comment

  1. maddalab – Posted July 26, 2009

    When the return type of a method is inferred and you don’t use an equals sign

    Implies that the return type can be specified without an equals sign as

    def two():Int { 2 }

    which is incorrect, results in a compile error

Add a comment

View 2 comments

  1. TimMacEachern – Posted June 23, 2009

    expresses => expressed

  2. deanwampler – Posted Aug. 22, 2009

    Thanks.

Add a comment

View 1 comment

  1. akaul791 – Posted Sept. 30, 2012

    0 or a nonzero digit followed zero or more digits (0-9) => 0 or a nonzero digit followed by zero or more digits (0-9)

Add a comment

View 1 comment

  1. Martin_Suesskraut – Posted June 9, 2009

    There is a dot within the last sentence (behind "inclusive)")

Add a comment

View 4 comments

  1. chifazo – Posted May 30, 2009

    According to this definition, a single period "." would be a valid floating point literal. There must be at least one digit before or after the period.

  2. TimMacEachern – Posted June 23, 2009

    expresses => expressed

  3. diathesis – Posted June 23, 2009

    "are expresses" should presumably be "are expressed"

  4. deanwampler – Posted Aug. 22, 2009

    Reworded.

Add a comment

View 1 comment

  1. misurakviktor – Posted Oct. 24, 2009

    What you think to be single quotes in the above example are not single quotes (except in '012').

Add a comment

View 3 comments

  1. misurakviktor – Posted Oct. 24, 2009

    The Unicode value u0027 does not match the character ’ above.

  2. razu – Posted Feb. 27, 2010

    backslash unicode is u005c

  3. bervyyl – Posted Nov. 4, 2010

    \\\ is equivalent to \u005c, not \u0009.

Add a comment

View 3 comments

  1. parthm – Posted June 1, 2009

    It would be good to have a short note on the kv._1, kv._2 notation used above for people don't know about accessing scala tuples

  2. deanwampler – Posted June 7, 2009

    Reworking the example to remove this use of tuples.

  3. dr_nailz – Posted Dec. 28, 2009

    with scala -> with scalac

Add a comment

View 2 comments

  1. hosamaly – Posted Aug. 21, 2010

    I tried the second line on scala-2.8.0.final, and it worked without need for the final space. For example:

    scala> println("""He exclaimed, "Scala is great!"""")
    He exclaimed, "Scala is great!"
    
  2. dmitrygusev – Posted Sept. 8, 2010

    Looks like the space before trailing """ isn't required in the seconds example. Here's the output of REPL:

    Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_13). Type in expressions to have them evaluated. Type :help for more information.

    scala> """He exclaimed, "Scala is great!"""" res0: java.lang.String = He exclaimed, "Scala is great!"

Add a comment

View 2 comments

  1. robcd – Posted June 20, 2009

    Copy and paste

  2. deanwampler – Posted July 12, 2009

    Thanks. Will fix.

Add a comment

View 3 comments

  1. argv – Posted Sept. 14, 2009

    In Java, string literals are always interned. Is this also true in Scala? If not, why not? If so, how are symbols different?

  2. argv – Posted Sept. 14, 2009

    In Java, string literals are always interned. Is this also true in Scala? If not, why not? If so, how are symbols different?

  3. vdichev – Posted Sept. 29, 2009

    Counterintuitive to what would be a common usage pattern in Ruby, Clojure, Erlang, it seems keys of maps is not the best way to use Symbol. Constructing a symbol instance leads to lookup in a WeakHashMap. It looks to me that using plain Strings is a much better option, especially given that, unlike Ruby, Java String's are immutable. If you care about performance, interned Strings might be an even better alternative. See also this ticket on Scala:

    http://lampsvn.epfl.ch/trac/scala/ticket/2358

    I'm not for deprecating Symbol entirely, but using them as a key in a map just so that the string is looked up in another map doesn't strike me as very efficient.

Add a comment

View 4 comments

  1. chifazo – Posted May 30, 2009

    Instead of saying: "because the parser thinks it is an incomplete integer literal", I think it should say: "because the parser thinks it is an incomplete character literal"

  2. parthm – Posted June 1, 2009

    It may be good to mention what Symbols are used for in Scala. Coming form Lisp I understand Symbols (assuming its the same in Scala) but cant really understand their use in Scala. If this is discussed in a later chapter/section maybe a pointer to it can be put.

  3. deanwampler – Posted June 7, 2009

    @Ariel. Right. Will clarify. @Parth. Will add a bit more on when they are typically used.

  4. jrimmer – Posted Aug. 26, 2009

    After the different explanation of all the other literals each with an accompanying example it's disjointing not to see an example provided for symbol literals.

Add a comment

View 2 comments

  1. nexusventuri – Posted March 13, 2010

    shouldn't it be 'id? in my browser i see ’id instead

  2. bhubbard – Posted Dec. 24, 2010

    Should that e.g. be in there? Looks like it should be:

    If you want to create a symbol that contains whitespace use scala.Symbol(" Programming Scala ") instead. All the whitespace is preserved.

Add a comment

View 4 comments

  1. TimMacEachern – Posted June 23, 2009

    You say "two or more items" at first, then "N between 1 and 22, inclusive". It would be nice to reconcile these statements. Does Scala not have the (1,) syntax for a single-element tuple?

    Also, you say "first-class" as if it's of extreme importance, but we newbie readers have no idea what you're talking about. Either leave it out to be dealt with later, or give us a hint as to what the alternative would be.

  2. diathesis – Posted June 23, 2009

    What happens if you declare a tuple of size > 22?

  3. diathesis – Posted June 23, 2009

    Apparently, this: :5: error: value Tuple23 is not a member of package scala

  4. deanwampler – Posted Aug. 22, 2009

    @Tim. Yes, the (1,) special syntax is only supported for Tuple1.toString. You have to explicit use "val t = Tuple1(1)" to create such a tuple.

Add a comment

View 2 comments

  1. javiervegeas – Posted June 14, 2009

    stay DRY: You can avoid repeating the "print the X item" statements using some cute loop like this

    (1 to tupleator.productArity).map((i:Int)=>"Print item number "+i+": "+tupleator.productElement(i-1)).foreach(println(_))

  2. deanwampler – Posted July 12, 2009

    True. I went for the "dumber", but slightly clearer approach here.

Add a comment

View 3 comments

  1. magle – Posted June 9, 2009

    Maybe it's a bit early here (concerning Pattern), but using t._N isn't considered good style imho. You could instead use Pattern Matching when declaring your tuple variables like this:

    val (myFirstItem, mySecondItem, myThirdItem) = tupleator("Hello", 1, 2.3)

    Now you could refer to each item using the given identifier separately, like

    println("Print the first item: " + myFirstItem ) println("Print the second item: " + mySecondItem ) println("Print the third item: " + myThirdItem )

  2. magle – Posted June 9, 2009

    ups ... forget my last comment!

    Just saw, that it's already there :o)

  3. buptwhisper – Posted Oct. 26, 2010

    t._N, the visiting element style of tuples. start with 1.

Add a comment

View 3 comments

  1. myrddin – Posted May 20, 2009

    Too times "in" at the end of the first sentence without the right object.

  2. parthm – Posted June 1, 2009

    The chapter/section number might be useful for "The Scala Type Hierarchy". Especially from the print copy.

  3. deanwampler – Posted June 7, 2009

    @Tobias, an unfortunate production error that has been fixed. Sorry. @Parth, we're working on putting numbers in the print version.

Add a comment

View 3 comments

  1. Martin_Suesskraut – Posted June 9, 2009

    Actually nil is an object in Ruby (instance of NilClass).

  2. deanwampler – Posted July 12, 2009

    Yes. I didn't mean to imply it wasn't ;)

  3. den – Posted June 5, 2010

    Java returns a reference to an object, not an object.

Add a comment

View 3 comments

  1. parthm – Posted June 1, 2009

    It may be good to have a small example here. This kind of approach is used only in some languages like Haskell (type Maybe) and showing example code will help understand the use better.

    scala> var x: Option[Int] = Some(1) x: Option[Int] = Some(1)

    scala> var y: Option[Int] = None
    y: Option[Int] = None

    scala> def foo(z: Option[Int]) = { | z match {
    | case Some(v) => v
    | case None => -1
    | } | } foo: (Option[Int])Int

    scala> foo(x) res10: Int = 1

    scala> foo(y) res11: Int = -1

  2. parthm – Posted June 1, 2009

    Oops. Sorry ... the above comment from me was premature.

  3. deanwampler – Posted June 7, 2009

    No problem. Thanks for going to the trouble...

Add a comment

View 1 comment

  1. ruanoj – Posted Dec. 26, 2010

    Code below needs importing scala.collection.Map in order to work (v2.8.1)

Add a comment

View 2 comments

  1. myrddin – Posted May 20, 2009

    Again two times "in"

  2. deanwampler – Posted June 7, 2009

    Sorry. Now fixed.

Add a comment

View 2 comments

  1. robcd – Posted June 20, 2009

    'the argument we passed to getOrElse'? Don't get the last sentence.

  2. deanwampler – Posted July 12, 2009

    Will improve the wording. thanks.

Add a comment

View 1 comment

  1. dmitrygusev – Posted Sept. 8, 2010

    In C# if you try to access map (which is really a System.Collections.Generic.Dictionary) element by key which isn't in a map you'll get KeyNotFoundException:

    var d = new Dictionary { {1, 2}, {3, 4} }; Console.WriteLine(d[1]); // Prints 2 Console.WriteLine(d[3]); // Prints 4 Console.WriteLine(d[5]); // throws KeyNotFoundException

Add a comment

View 3 comments

  1. Manfred_Endrullis – Posted Oct. 25, 2009

    delete one "of" at "... of of Map"

  2. awregan – Posted Oct. 29, 2010

    duplicated "of" after "concrete subclass"

  3. awregan – Posted Oct. 29, 2010

    Duplicated "of" near "concrete subclass"

Add a comment

View 2 comments

  1. GatesDA – Posted July 14, 2009

    Some is a case class, so the new keyword is unnecessary. If you just don't want to get into that yet, it does make sense to leave it in.

  2. deanwampler – Posted Aug. 22, 2009

    Right, that's why I wrote it this way.

Add a comment

View 4 comments

  1. po6eynj02 – Posted Oct. 10, 2009

    Wait a second. How is this being parsed? Is there something special about one-letter upper-cased types? Or are all unknown type names just considered parametric types? What might happen if someone defined an "A" or "B" class in the package? Might there be conflicts?

    There's probably good responses for these questions. Just wishing it was in the above paragraph.

  2. ldeck – Posted Oct. 19, 2009

    A and B are the generic types defined for the Map itself where 'A' represents the type for the key and 'B' represents the type for the value stored for that key.

    e.g., if you create a map as follows: new Map[String, Integer]

    then A would be a String and B an Integer.

  3. kadi – Posted Nov. 19, 2010

    I don’t think that the type of B is inferred here. The type is simply picked from the surrounding generic class, isn’t it?

  4. kadi – Posted Nov. 19, 2010

    I don’t think that the type of B is inferred here. The type is simply picked from the surrounding parameterized class, isn’t it?

Add a comment

View 4 comments

  1. magle – Posted June 10, 2009

    ... those files (declaring the same package) even dont have to reside in the same directory but could be spread all over the directory structure.

  2. bieffe – Posted July 10, 2009

    Maybe it should be mentioned here that when you compile a file with a package definition in it, the scalac compiler creates a sibdirectory and puts the .class files in it (I don't think that javac does the same ).

  3. deanwampler – Posted July 12, 2009

    We get into this later on.

  4. ldeck – Posted Oct. 19, 2009

    Worth putting a note in, I think, that whilst this might be more flexible it could also pose a danger in the form of structure-mess. e.g., it could make a class harder to discover.

Add a comment

View 1 comment

  1. jrduncans – Posted July 14, 2009

    Might be nice to indicate that Java syntax also works the Java way: it applies to whole file, it has to come first, etc. At first I wasn't certain if it worked more like the Ruby private keyword, where the package would apply until you declared another.

Add a comment

View 1 comment

  1. dmitrygusev – Posted Sept. 8, 2010

    In Class311 there should probably be

        def m = "m31"
    

Add a comment

View 6 comments

  1. hotdog – Posted July 14, 2009

    This paragraph is confusing. It would be fine to note, that it's not relative in a way e. g. hrefs are relative, but instead "a package reference starting in a name p will be looked up in the closest enclosing scope that defines a member named p." (Scala Language Reference p. 118)

  2. deanwampler – Posted Aug. 22, 2009

    Will clarify

  3. EdStaub – Posted Sept. 17, 2009

    I've seen notes on the Web that indicate that relative imports are going away in 2.8. I can't find anything definitive, though.

  4. robertkuhar – Posted Sept. 29, 2009

    Doesn't compile in scala 2.8 as the scala.collection has no jcl subpackage.

    scalac relative-imports.scala relative-imports.scala:5: error: value jcl is not a member of package collection import root.scala.collection.jcl._ // full path from real "root" ^

  5. imho – Posted Dec. 2, 2010

    Unclear. You say imports are relative, but you never actually say what imports are relative to. Are they relative to the import on the previous line or what?

  6. karelbilek – Posted March 18, 2012

    I am completely confused by this part, as people before me already noted.

Add a comment

View 4 comments

  1. derekmahar – Posted Aug. 7, 2009

    Remove second "the" in "to the last the import statement" in "check that the statement is properly relative to the last the import statement".

  2. deanwampler – Posted Aug. 22, 2009

    Thanks.

  3. cgrigis – Posted June 17, 2010

    Typo: "... check that the statement is properly relative to the last the import statement..."

  4. cgrigis – Posted June 17, 2010

    Typo: "... check that the statement is properly relative to the last the import statement ..."

Add a comment

View 1 comment

  1. derekmahar – Posted Aug. 7, 2009

    In the last sentence, "if the declaration is Foo[-A]" simply repeats your first point in the same sentence. Would it make more sense if you were to replace "if the declaration is Foo[-A]" with "for any B that is a subtype of A" as in the preceding sentence?

Add a comment

View 3 comments

  1. chifazo – Posted May 30, 2009

    Generics were added to Java in version 5.0, which was released in 2004, not in the late 90's.

  2. deanwampler – Posted June 7, 2009

    Right. Will fix.

  3. Ragnvald – Posted Sept. 26, 2009

    Type less, do more? The text is cluttered with forward references to chapter 12. We will explore (...) in chapter 12, we can explain it in depth in chapger 12, we dive into their details in chapter 12, bla bla bla.

Add a comment

View 1 comment

  1. Daniel Capra – Posted Nov. 15, 2012

    Not quite all members: it looks like it is possible to have a concrete class with an undefined type. You can't use the type until you've firmed it up in a subclass, but you can still instantiate the class and use other parts of it:

    class Concrete {

    type MyType

    def echo(in:MyType):MyType = in

    def stringEcho(in:String):String = in

    }

    class Sub extends Concrete {

    type MyType = String

    }

    var concrete = new Concrete()

    println(concrete.stringEcho("hello"))

    var sub = new Sub()

    println(sub.echo("hello again"))

    Edited on November 15, 2012, 4:08 a.m. PST

Add a comment