A Concise Introduction to Scala
Copyright © 2011, 2013 David Matuszek

Arrays
Classes
Console I/O
Data Types
Declarations
Expressions
File I/O

Function Literals
General
GUI Programs
Higher-order functions
Identifiers
Input/Output
Lists

Maps
Methods
Numbers
Objects
Options
Program Structure
Running Scala
Scalatest
Scripts
Sets
Statement Types
Strings
Traits
Tuples

General

Running Scala

In a Java application, you need a public static void main(String[] args) method. In a Scala application, you need a def main(args: Array[String]) method.

How to run Code Results/Comments
On the command line as a REPL (Read-Eval-Print-Loop).
dave% scala
Welcome to Scala version 2.7.7.final (Java ↙ HotSpot(TM) 64-Bit Server VM, Java 1.6.0_17). Type in expressions to have them evaluated. Type :help for more information. scala> 2+2 res0: Int = 4 scala> exit

No main method is required in this case.

 

As a script.
println("Hello from a script.")
dave% scala HelloScript.scala
Hello from a script.
Scala automatically wraps your lines in a class and a main method, so don't do this yourself.
As a shell script.
#!/usr/local/share/bin/scala
println("Hello from a script.")
This is the correct location for Scala on my Mac, but it doesn't work for me. (Should try it on UNIX and Windows).
As an application.
object HelloApp extends App {
  println("Hello, World!")
}
dave% scalac hello.scala
dave% scala HelloApp
Hello, World!
File name doesn't have to be the same as the application name. The App trait wraps your code in a main method.
As a single object.
object HelloObject {
  println("In object")
  
  def main(args: Array[String]) {
    println("In main")
  }
}
dave% scalac HelloProgram.scala
dave% scala HelloObject
In object
In main
As a program.
class HelloClass {
  def inClass() {
    println("In class")
  }
}

object HelloObjectPlusClass {
  println("In object")
  
  def main(args: Array[String]) {
    println("In main")
    val c = new HelloClass
    c.inClass()
  }
}
dave% scalac HelloWithClass.scala
dave% scala HelloObjectPlusClass
In object
In main
In class

The object may not have the same name as the class!

scalac is the compiler. You can use fsc instead, which remains in memory and so is faster (after the first use).

Identifiers

Scala has four types of identifiers:

Alphanumeric identifiers:
Operator identifiers:
Mixed identifiers:
Literal identifers:

Declarations

All variables must be declared, with either var (if the value may change) or val (for constants). In Scala, val is preferred, unless you have good reason to use var. If given an initial value in the declaration, the variable's type is inferred and need not be explicitly stated (but it may be). If explicitly stated, the type comes after the variable and a colon, for example, var q: Boolean = true.

The types of variables must be declared:

Type parameters (generics) are enclosed in square brackets, for example, Array[Int].

Within a method, variables must be given an initial value. Variables within a class (and not within a method) may optionally be given an initial value.

When initial values are not given, new is required: val ary = new Array[Int](5)
    and default values of zero, false, or null are used.
When initial values are given, new is not allowed: val ary2 = Array(3, 1, 4, 1, 6)

The type of a function is written with the double-headed arrow, => or the Unicode version, . Except in the case of a single argument, parentheses are required:

Data types

Scala has no primitives, only objects.

Numbers

Char, Byte, Short, Int, Long, Float, Double are considered to be numeric types. The default type for integers is Int, and the default type for "real" numbers is Double. The less accurate forms are converted to Int or Double when arithmetic is performed using them.

All numbers are stored internally in a binary representation, but they may be written in various ways.

Operations on numbers include + (addition), - (subtraction or negation), * (multiplication), / (division), and % (modulus). Operations on integers also include << (left shift), >> (right shift with sign extension), >>> (right shift with zero fill), & (bitwise and), | (bitwise or), and ^ (bitwise exclusive or).

Strings

A String may be enclosed in double quotes, "...", or in triple double quotes, """...""". The latter is a raw string (that is, \ does not "escape" characters) and may contain newlines.

A Symbol is an interned string. A symbol literal starts with a single quote, ', followed by a letter, then zero or more letters and digits.

Lists

Lists are the most valuable data type in any functional language, including Scala.

Much of the following information is from http://anders.janmyr.com/2009/10/lists-in-scala.html.

Lists are:

When it is necessary to specify the type of a list, write it as List[Type]. A literal list is written as List(value, ..., value).

Fundamental (efficient) list methods are:

Functions defined in terms of the above include:

Higher-order functions

The following functions are described as operations on lists, but most of them will operate on many types of sequences.

Tuples

A tuple consists of from 2 to 22 comma-separated values enclosed in parentheses. Tuples are immutable. To access the n-th value in a tuple t, use the notation t._n, where n is a literal integer in the range 1 (not 0!) to 22. There may be a spaces around the dot, but not between _ and n.

Sets

Sets are immutable by default. Mutable sets may be imported from scala.collection.mutable. There are a great many operations on sets, of which contains, isEmpty, intersect, union, and diff are just a few.

Maps

Maps are immutable by default. Mutable maps may be imported from scala.collection.mutable. A map is represented as a list of pairs, that is, Map((key, value), ..., (key, value)). A more expressive syntax for writing the same thing is Map(key -> value, ..., key -> value).

The basic operations on maps are (1) getting the value associated with a key, and (2) for mutable maps, associating a value with a key. Most list operations can also be used on maps.

Options

Options are used when an operation may or may not succeed in returning a value. Options are parameterized types, so one may have, for example, an Option[String] type. The possible values are Some(value), where the value is of the correct type, or None, for the case where no value has been found.

Although a few operations are defined for Option types, it is far more common to use a match expression to extract the value, if one exists.

Arrays

Arrays are mutable. The advantage of arrays is fast access to random elements. Unless this feature is needed, consider using Lists instead.

An array may be created by listing its values:

or by explicitly giving its type, and using new to indicate its size:

The basic operations on arrays are getting a value from it, storing a value in it, and getting its length. Note the use of parentheses instead of brackets.

Multidimensional arrays

To create a multidimensional array, import Array._, then call ofDim[element_type](dimensions). The elements of a multidimensional array can be accessed using the syntax arrayName(firstIndex)(secondIndex)...(lastIndex).

Expressions

If expressions

The value of the if expression is the value of the expression that is chosen; or, if no condition is satisfied and there is no else clause, the value is the Unit value, ().

For expressions (known in other languages as list comprehensions)

The for expression is used to create and return a sequence of results. The syntax is for (seq) yield expression, where:

Examples:

Match expressions

Syntax:

expression match {
    case pattern1 => expression1
    case pattern2 => expression2
    ...
    case patternN => expressionN
}

The match expression uses pattern matching to select a case, then the value of the match expression is the value of the corresponding expression. Patterns may be:

Cases are tried in the order in which they occur. When a case is selected, the code for that case, and only for that one case, is executed.

Statement types

Scala does not have "statements," it has expressions, and every expression has a value. However, some expressions are executed purely for their side effects, and return the Unit value, (), which is essentially meaningless. Such expressions are basically the same as statements in other languages.

Syntax Example Comments
{ expressions } { temp = a; a = b; b = temp } A compound expression consists of one or more expressions enclosed in braces. The value of a compound expression is the value of the last expression evaluated within it; all other expressions are evaluated only for their side effects. The value of a compound expression may or may not be Unit.
var name: type = value var abc = 5 Variables must be given initial values, except when within a class.
var name: type var abc: Int Allowable within a class.
val name: type = value val five = 5 val declares a constant, which must be given a value; explicit type information is allowed but redundant. A val name for an object is constant in the sense that the name cannot be reassigned; but the contents of the object may be modified.
name = expression abc = 10 Values may be assigned only to var variables.
name += expression abc += 1 All the various op= operators are allowed. ++ and -- do not exist in Scala.
if (condition) expression
else if (condition) expression
else expression
if (x < 0) {
  println(x)
  x = -x
}
else x = x + 1
Zero or more else if clauses may be used, and the final else is optional. Braces can be used to group several expressions into a single compound expression. The value of the if is the value of the last expression evaluated within it (which may be Unit).

If there is no final else, the type of the expression is Any, regardless of whatever value it may have.
while (condition) statement
var x = 1
while (x < 1000)
  x *= 2
Nothing unusual to note. However, Scala has no break or continue statements.
do { statements } while (condition)
var x = 1
do {
  x *= 2
} while (x < 1000)
    
Nothing unusual to note. However, Scala has no break or continue statements.
for (variable <- list) statement
for (x <- ary)
  println(x)
The parenthesized expression may contain tests, assignments, and additional generators (variable <- list expressions).
for (variable <- min to max) statement
for (i <- 1 to 10)
  println(i)
to is a method of RichInt. to is inclusive; until excludes max.
for (variable <- min to max if condition)
statement
for (i <- 1 to 15 if i % 2 == 0) print(i) for comprehensions may have guards.
return expression
return true

Returns a value from a method. Use of return requires that the return type of the method be explicitly stated.

throw new Exception throw new IllegalArgumentException As in Java.
try { expressions }
catch {
case name: Exception => {...} ...
case name: Exception => {...} }
finally {...}
try {
  val f = new FileReader("input.txt")
} catch {
  case ex: FileNotFoundException => {
    println("Missing file exception")
  }
  case ex: IOException => {
    println("IO Exception")
  }
  finally {
    println("Exiting finally...")
  }
}

The Exception is the exception type, and the name is a variable holding the exception that occurred.

As in Java, you should have one or both of catch and finally; usually you won't want both.

This example is from TutorialsPoint.

Methods

Syntax:

access may be private, protected, or public by default.

The return type of a method can usually be omitted; it must be declared:

For reasons of clarity, it is usually best to declare the return type.

Braces around the body may be omitted if the body consists of a single expression, whose value is to be returned.

Methods may be overloaded, as in Java.

Inherited methods may be overridden, in which case the method definition must be preceded by the keyword override.

The parameters of a method or function are treated as if they were defined by val; they cannot be reassigned a new value.

Function literals

Syntax: (arg1: Type1, ..., argN:TypeN) => expression

Passing function literals as arguments

Within an enclosing argument list, the parentheses around the parameter list can usually be omitted.
Example: "aBcDeF".map(x => x toLower)

If each parameter is used only once, and the parameters appear in the expression in the same order as in the parameter list, the parameter list may be omitted, and underscores may be used in the expression.
Example: "aBcDeF".map(_ toLower)

Passing methods as functions

Methods can often be passed as if they were functions, for example, "abc" map println works. In other cases, the method name must be followed by an underscore to convert it to a "partial function," for example, "abc" map (println _).

Methods are functions that belong to objects, and as such, can manipulate the fields of their object. Methods that do this should not be used as functions.

Program structure: Classes, Objects, Traits and Scripts

Scripts

A script is a list of commands that can be interpreted directly by the Scala system. Scala wraps the script in a main method and executes it immediately. The syntax for running a script is simply scala myScript.scala.

Classes

A class describes objects, as in Java. A class may extend one other class, and it may include any number of traits. A class has a primary constructor, which is part of the class declaration itself.

class Foo { ... }
By default, a class extends AnyRef.
class Foo(name: String) { constructor_body }
The primary constructor is part of the class header. Parameters are put after the class name, and the constructor body is the entire class body.
class Foo(a: Int, var b: Int, val c: Int) { ... }
Constructor parameters are handled as follows. Automatically, all parameters are automatically declared as private fields; a has private getters and setters; var b has public getters and setters; and val c has a public getter. A setter method for a parameter v has the name v_=.
def this(parameters1) { this(parameters2); ... }
Auxiliary constructors are defined with this; the first statement in the auxiliary constuctor must be a call to some other constructor.
class Foo(a: Int, b: Int) extends Bar(a + b) { ... }
When extending a class, any base class (=superclass) parameters are provided immediately.
class Dog(name: String) extends Animal with Friend { ... }
A comma-separated list of traits can follow the keyword with. Any uninitialized vars and vals defined by the trait must be initialized by the class.

Objects

In addition to creating objects from classes, you can declare objects. An object is declared like a class, but with the keyword object instead of class; also, an object cannot take parameters. Whereas a class declaration describes a blueprint for objects, an object declaration declares a single object.

A program, other than a script, must contain an object with a main(args: Array[String]) method.

When you define a class and create objects from it, you use the keyword new:

scala> class Dog(name: String)
  defined class Dog

scala> val a = new Dog("Fido")
  a: Dog = Dog@a80370d
But when you create an object "literal", you don't use new:
scala> val t = Tuple(1, "apple")
t: (Int, java.lang.String) = (1,apple)

scala> val l = List(1, "apple")
l: List[Any] = List(1, apple)

scala> val s = Set(1, "apple")
s: scala.collection.immutable.Set[Any] = Set(1, apple)

Traits

Traits are declared like classes, used like Java interfaces, and may contain fully-defined methods. In the declaration of a class (or object), if the superclass is mentioned, the syntax is class ClassName extends SuperClass with Trait1,...,TraitN, otherwise the syntax is ClassName extends Trait1 with Trait2,...,TraitN

Input/Output

Console

val data = readLine // Reads a single line (as a String) from the Console
val data = readLine(prompt) // Prints the prompt, then reads a line

Note: In the REPL, readLine does not display the text being entered.

print(data)    // Prints to the Console without a newline
println(data)  // Prints to the Console with a newline
println        // Just prints a newline

Text files

Finding a file to read or write

import scala.swing.FileChooser, java.io.File
val file = new File(fileName)   // with a relative or absolute path
val chooser = new FileChooser
val response = chooser.showOpenDialog(null)  // to read a file
val response = chooser.showSaveDialog(null)  // to write a file
if (response == FileChooser.Result.Approve) {
val file = chooser.selectedFile }

Reading from a text file

import scala.io.Source, scala.io.Source._
val stream = Source.fromFile(file or fileName)
for (char <- stream) {
process each character }
for (lines <- stream.getLines) { process each line }
val all = stream.getLines.toList         // as a list of strings
val all = stream.getLines.mkString       // as a single string
val all = stream.getLines.mkString("\n") // with newlines
stream.close

Writing to a text file

import java.io.PrintWriter
val stream = new PrintWriter(file or fileName)
stream.print(data)

stream.println(data)
stream.println
stream.close

Scalatest

Here is one setup that is currently working for me:

And a working test file:

package fractionTest

import org.scalatest.FunSuite
import Fraction._

class ExampleTests extends FunSuite {
  
  val f1 = Fraction(1, 2)
  val f2 = Fraction(1, 4)
  
  test("Test multiplication") {
    assert(f1 * f1 == f2)
  }
  
  test("Test bad multiplication") {
    assert(f1 * f2 == f2)
  }
}

GUI Programs

Here is a template for a GUI program:

import scala.swing._
import event._

object SampleGUI extends SimpleSwingApplication {
  def top = new MainFrame {  // top is a required method
    title = "A Sample Scala Swing GUI"
    
    val label = new Label { text = "---------------" }
    val button = new Button { text = "Click me" }
    
    contents = new FlowPanel {
      contents += label
      contents += button
    }
    
    listenTo(button)
    
    reactions += {
      case ButtonClicked(button) =>
        label.text = "You clicked!"
    }
  }
}

MainFrame extends Frame with RootPanel with Publisher. MainFrame includes:

  From Frame From RootPanel From Publisher
Values     listeners
    reactions
Methods contents_=(c: Component): Unit contents : Seq[Component] (at most one component) listenTo (ps : Publisher*) : Unit
title : java.lang.String contents_= (c : Component) : Unit deafTo (ps : Publisher*) : Unit
menuBar_=(m: MenuBar): Unit font_=(f : java.awt.Font) : Unit  

Here are some Components:

Component type Vals and vars Methods
class Button(text0 : java.lang.String)
extends AbstractButton
listeners
reactions
class TextField(text0 : java.lang.String, columns0 : Int)
extends HasColumns
listeners
reactions
class TextArea(text0 : java.lang.String, rows0 : Int, columns0 : Int)
extends HasColumns with HasRows
listeners
reactions
text : java.lang.String
text_=(t : java.lang.String) : Unit
editable_=(x : Boolean) : Unit
class CheckBox(text : java.lang.String)
extends ToggleButton
listeners
reactions
selected : Boolean
selected_=(b : Boolean) : Unit
class ButtonGroup(initialButtons : AbstractButton*)
extends AnyRef
buttons : Set[AbstractButton] select (b : AbstractButton) : Unit
selected : Option[AbstractButton]
class ComboBox[A](items : Seq[A])
extends Component
listeners
reactions
object selection extends Publisher
class MenuBar
extends Wrapper
contents
listeners
reactions
class Menu(title0 : java.lang.String)
extends MenuItem with Wrapper
contents
listeners
reactions
class MenuItem(title0 : java.lang.String)
extends AbstractButton
listeners
reactions
     
     
     
Panel/Layout Example
class BorderPanel
extends Panel with LayoutContainer
contents = new BorderPanel {
  add(label, BorderPanel.Position.North)
  add(button, BorderPanel.Position.East)
  add(text, BorderPanel.Position.Center)
}
class BoxPanel(orientation : Value)
extends Panel with Wrapper
contents = new BoxPanel(Orientation.Vertical) {
  contents += label
  contents += button
  contents += text
}
class FlowPanel(alignment : Value)
extends Panel with Wrapper
contents = new FlowPanel(Orientation.Vertical) {
  contents += label
  contents += button
  contents += text
}
class GridBagPanel
extends Panel with LayoutContainer
class GridPanel(rows0 : Int, cols0 : Int)
extends Panel with Wrapper
contents = new GridPanel(2, 2) {
  contents += label
  contents += button
  contents += text
}

All Panels have: contents, listeners, reactions, contents, tooltip_=, listenTo, deafTo.
All LayoutContainers have add (comp : Component, c : Constraints) : Unit.