The Scala language

How do I import?

The following imports class Map from package scala.collection.mutable:

import scala.collection.mutable.Map

We can import several classes from the same package in a single statement:

import scala.collection.mutable.{Map, Set, Buffer}

We can import all classes in a package, using the _ wildcard:

import scala.collection.mutable._

We can also rename imports:

import scala.collection.mutable.{Map => MutableMap}

and with a similar notation, exclude specific classes:

import scala.collection.mutable.{_, Map => _, Set => _}

The latter imports everything from package scala.collection.mutable, except Map and Set.

Scala’s imports are relative and thus we can import everything from scala.collection and scala.collection.mutable with:

import scala.collection._
import mutable._

Since package scala is imported implicitly anyway, we can also write the above as:

import collection._
import mutable._

To make package names absolute, we can prefix them with _root_:

import _root_.scala.collection.mutable.Map

We may import Java packages:

import java.beans.XMLEncoder
import javax.swing.JTable

(or .NETs when compiled to that VM)

An example scala file:

import collection.mutable.{Map => MutableMap}  //alias an import
import _root_.scala.collection.immutable.Map   //non-relative import
import scala.concurrent.{Lock, Channel}        //imports both scala.concurrent.Lock and scala.concurrent.Channel
import scala.Array._                           //imports all members of object Array 
 
object ImportExample extends Application {
  
  val mmap = MutableMap("one" -> 1, "two" -> 2, "three" -> 3)
  assume(mmap.isInstanceOf[scala.collection.mutable.Map[String, int]]) 
  
  val imap = Map("one" -> 1, "two" -> 2, "three" -> 3)
  assume(imap.isInstanceOf[scala.collection.immutable.Map[String, int]]) 
  
  val source = Array(1, 2, 3)
  val target = Array(1, 5, 3)
  copy(source, 1, target, 1, 1)//copy method was imported
 
 
  //import an instance's members
  class Cat {
    val catName = "fluffy"
    def meow {
      println("meow")
    }
  }
  
  val cat = new Cat
  //import the instance's members
  import cat._
      
  meow
  assume(catName == "fluffy")
 
}

How do I write a loop?

There are two ways to write simple integer loops:

for (i <- 0 until 1000000) { ... }
var i = 0; while (i < 1000000) { ...; i = i+1 }

The second can be more efficient, but the first is usually considered as cleaner code. To make the loop include 1000000, use to instead of until.

Using higher-order functions defined in scala.Iterable and elsewhere (scala.List in particular) can often replace for the best a more traditional loop.


For-comprehensions are translated into a series of calls to the functions map, flatMap and filter of the originating object (see ScalaRef 6.16).

for(n <- List( 5, 7, 2, 4) if n % 2 == 1) yield n * n

is equivalent to

List(5, 7, 2, 4).filter(n => n % 2 == 1).map(n => n * n)

Lazyness and Eagerness in for comprehensions

The results may seem surprising in the following for comprehension:

var done = false
for { i <- List(1,2)
     if !done } {
       println(i+" "+done)
       assert( !done )
       done = true
}

There is a second iteration and an assert, even though done is set to true after the first iteration. This is due to the expanded List.filter( x ⇒ !done ) being strictly (eagerly) evaluated, where done is “false” during the call to filter (i.e. no actual iteration has taken place yet).

Using List(1,2).projection or “1 to 2” forces lazy evaluation, i.e. for each iteration the next element is evaluated. and works as expected. see list-manipulation for more details on lazy vs eager for lists.

It should be noted that using code with such side effects can also reduce composibility of a given comprehension (whether used inside a for or by calling filter etc by hand).

Also important is that lazy vs strict evaluation can exhibit different performance characteristics (in terms of both memory usage and processing time) for different code. If in doubt profile.

How do I use exceptions?

An exception (actually an instance of Throwable) can be caught in a catch clause. The specific exception type is detected using pattern matching:

try { 
  ... 
} catch {
  case ioe: IOException =>
    ... // more specific cases first !
  case e: Exception =>
    ...
}

Java’s catch clauses are really nothing more than a limited form of pattern matching.

What is the difference between a case and a normal class?

  • You can do pattern matching on its name and its constructor parameters (this is usually the important point). A normal class can only be matched by name - any condition on its members have to be in the guard clause.
  • You can construct instances of these classes without using the new keyword.
  • All constructor arguments are accessible from outside using automatically generated accessor functions.
  • The toString method is automatically redefined to print the name of the case class and all its arguments.
  • The equals method is automatically redefined to compare two instances of the same case class structurally rather than by identity.
  • The hashCode method is automatically redefined to give equal values for instances that are the same when compared with equals.

Since Scala 2.7.0 a case class can extend a case class.

Case classes are commonly used to create user-defined value types – data structures, if you will. Some obvious examples might be complex numbers or street addresses. Objects of a value type are identified by their data values, not by their memory addresses. Value types typically have no mutable state because value objects whose data values are immutable can safely be duplicated and shared at will. Unrestricted duplicating and sharing is crucial for data that has to be stored on disk or transmitted to a different program or different computer. Value types certainly can be defined as ordinary classes, but using case classes simplifies the process.

Why can't I use the word "scala" in my package names?

You must have a stone-age version of scala... since quite a while, there is a _root_ package which is used internally to find the parts of the scala library all programs depend on. Hence, it is possible to use scala in package names now, if the urge should arise.

How do I use Tuples?

You can group expressions without the need to create new classes

object Test extends Application {
  def tupleTest = (1, 2, 3)
 
  val (a, b ,c) = tupleTest
  println("a:" + a + ", b:" + b + ", c:" + c)
    
  val t = tupleTest
  println("a:" + t._1 + ", b:" + t._2 + ", c:" + t._3)
}

Above, tupleTest is of type Tuple3[Int, Int, Int] which can be written as [Int, Int, Int]. This shorthand syntax was introduced in Scala 2.4. Before, there was no special syntax for tuples. They had to be created as any other case class, e.g., through Tuple3(1, 2, 3) or through the unnumbered generator Tuple(1, 2, 3). Both forms are still available.

Tuple1 to Tuple22 are defined. Pair can be used as Tuple2. Triple can be used as Tuple3.

How do I use Lists?

There are two ways to write lists, one using the infix operator ::, and the other using the List constructor. Their meaning is the same, and you can use both ways in pattern matching

  val t = List( 1, 2, 3, 4, 5)        
  val u = 1 :: 2 :: 3 :: 4 :: 5 :: Nil
  t match {
    case 1::2::rest        => true
    case List(1,2,rest@_*) => true // equivalent
  }

How do I use Maps?

immutable

      val immutable = Map(1 -> "one", 2 -> "two", 3 -> "three")
      
      //assignment returns a new map
      val map2 =  immutable(2) = "2"
        
      assume(immutable == Map(1 -> "one", 2 -> "two", 3 -> "three"))
      assume(map2 == Map(1 -> "one", 2 -> "2", 3 -> "three"))

mutable

  val map = new scala.collection.mutable.HashMap[String, Any]
            
  map("likes") = "cheese"
        
  assume( map("likes") == "cheese")
  assume( map.get("likes") == Some("cheese") )
      
  assume( map.get("fakeKey") == None)
      
  map += "name" -> "Gromit"
  assume( map("name") == "Gromit")
 
  map += "id" -> 1234
  assume( map.get("id") == Some(1234) )
  assume( map("id") == 1234)
 
  map.get("id") match {
    case Some(idval) => assume(1234 == idval)
    case None => fail("no value found")
  }

Map keys

  //custom classes as keys to a map
  case class AnotherCustomKey(someval:int, someString:String) {
    //hashCode and equals are implemented for you
  }
  
  val map = new HashMap[AnotherCustomKey, int]
  map += AnotherCustomKey(1,"333") -> 1   
  assume(map.get(AnotherCustomKey(1, "333")) == Some(1))
  assume(map.get(AnotherCustomKey(2, "222")) == None)
 
  //if a case class can not be used, you must override equals and hashCode
  class CustomKey(val someval:int) {
    override def hashCode: int = someval
    override def equals(any:Any): Boolean = {
      any.isInstanceOf[CustomKey] && any.asInstanceOf[CustomKey].someval == someval
    }
  }
  val map2 = new HashMap[CustomKey, int]
  map2 += new CustomKey(1) -> 1   
  assume(map2.get(new CustomKey(1)) == Some(1))
  assume(map2.get(new CustomKey(2)) == None)

How do I specify Preconditions, Assertions and Unrecoverable errors?

There are some predefined functions for this, no need to import them.

For preconditions you can use the functions assume( cond:Boolean) and assume( cond:Boolean, msg:String)

    def sqrt( v: Double) = {
      assume( v >= 0, "sqrt parameter must be non-negative")
      Math.sqrt( v) ;    
    }

You have also assert( cond:Boolean) and assert( cond:Boolean, msg:String)

There is a compiler switch -noassert to skip asserts and assumptions on final executables.

For unrecoverable errors there is the function error( msg: String) that throws an Error

For recoverable exceptions you can derive java.lang.RuntimeException

How do I access and update an Array?

In Scala, array access are made using the syntax of normal method calls.

val x = Array(3,2,1);
assert(x(0) == 3)
assert(x(1) == 2)
assert(x(2) == 1)
x(0) = 4

Array is just treated like a normal object: it has any apply method (which is called in an expression like x(0)), and an update method (which is the spelled out version of the statement x(0) = 4).

Can I use the fancy method syntax for array access in my code, too?

There is nothing that prevents you from making use of this trick. Below is a program that demonstrates how an object can be turned into something like a dictionary. For real dictionaries, using the collection.Map types is preferrable of course.

object dictionary {
 val data = Array(null, "A","B","C")
 
 def apply(x:String) = x match {
  case "one" => data(1)
  case "two" => data(2)
  case "three" => data(3)
 }
 
 def update(x:String,y:String) = x match {
  case "one" => data(1) = y // ...this gets turned to data.update(1,y)
  case "two" => data(2) = y
  case "three" => data(3) = y
 }
 
 def main(args:Array[String]) { // ...shorthand for this.apply("one")
   Console.println(this("one")+","+this("two")+","+this("three")) 
   this("one") = "X"   // ...and this becomes this.update("one","X")
   this("two") = "Y"
   this("three") = "Z"
   Console.println(this("one")+","+this("two")+","+this("three"))
 }
}

What's the difference between a lazy argument, a no-arg function argument, and a lazy value?

A method with a “normal” (call-by-value) argument is declared like this

  def foo(x:Bar) = {
    val a = x
    val b = x
  }

Whenever foo is called with an expression such as the “abc” in foo(abc), the expression abc will be evaluated once and the result will be passed to foo. The variables x, a, and b will all be references to the same result value.

A method with a lazy (call-by-name) argument is declared like this

  def foo(x:=>Bar) = {
    val a = x
    val b = x
  }

In this case, when foo(abc) is executed, abc won’t be evaluated before foo is called. Instead, x will be equivalent to the expression “abc” rather than the value that abc returns. So in the code above abc will be evaluated twice. The first result will go into the variable a, the second will go into the variable b.

A method that takes a no-argument function (a thunk) is declared like this

  def foo(x:() => Bar) = {
     val a = x
     val b = x
     val c = x()
  }

To call foo(abc), abc must be a function or evaluate to a function. As with call-by-name, the function will not be evaluated before calling foo. In that sense it looks like a call-by-name lazy argument and in fact call-by-name is implemented as a thunk “under the hood.” The difference is that with explicit thunks the assignments to a and b only create aliases to the abc function, they don’t evaluate the function. To evaluate the function an expression like the assignment to c must be used.

Lazy values allow you to turn call-by-name lazy arguments into call-by-need lazy arguments.

   def foo(x: => Bar) = {
     lazy val a = x
     //...
   }

If foo(abc) is executed then using x anywhere in the method will normally cause a (re)evaluation of the abc expression. However, the assignment of x to the lazy value a does not cause abc to be evaluated. Instead, the first use of a will cause abc to be evaluated but each subsequent use of a will reuse the same result.

I'm a Java programmer. How do I learn Scala?

Here are some relatively brief tutorials and references you can use:

Rather more extensive is “Scala by Example”, a PDF (150+ pages) by Martin Odersky that is included with the Scala documentation package.

More extensive still is the book Programming in Scala by Martin Oderksy, Lex Spoon, and Bill Venners. It is over 500 pages long. The book is not completely finished yet (as of April 2008) but you can purchase a PDF of the current draft from http://www.artima.com/shop/forsale .

See also the Scala/Java interoperability FAQs

 
faqs/language.txt · Last modified: 2008/06/18 13:15 by 212.76.40.142
 
Recent changes RSS feed Valid XHTML 1.0 Driven by DokuWiki