A Concise Introduction to Scala
Copyright ©2010, David Matuszek
In a Java application, you need a method. In a Scala application, you need a method.
| How to run | Code | Results/Comments |
|---|---|---|
| On the command line as a REPL (Read-Eval-Print-Loop). | dave% scala |
No
|
| As a script. | println("Hello from a script.") |
dave% scala HelloScript.scalaScala 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!
|
Scala has four types of identifiers:
$' counts as a letter, but is reserved for use by Scala.vals) are
camel case and begin with a capital.abc123, myVar, myVal, myMethod,
MyClass, MyObject, Pi, E.
( ) [ ] { } ' " _ . , ; , `:) are right-associative, all others are left-associative.+ => <?> :::
unary_+ , myVar_= ` character).`Hello, World!`, `class`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:
() => return_typearg_type => return_type or (arg_type) => return_type(arg_type_1, ..., arg_type_N) => return_typeScala has no primitives, only objects.
Any
AnyVal
Boolean, Char, Byte, Short, Int, Long, Float, Double (these are as in Java)Unit (has only a single value, (); returned by functions that “don't return anything.”)AnyRef (corresponds to Object in Java)
ScalaObject
scala.* reference types, including Array and ListNull (bottom of all AnyRef objects)Nothing (bottom of Any)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 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:
List[Nothing].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).
list.head returns the first element in the list.list.tail returns the rest of the list, minus the head.value :: list (:: is pronounced “cons”) puts the value as the new head of the list. It is right-associative.
List() or as Nil. List(1, 2, 3) is equivalent to 1 :: 2 :: 3 :: Nil.list.isEmpty checks if the list is empty.list.length returns the number of elements in the list.list.last returns the last element of the list.list.init returns a list with the last element removed.list.take(n) returns a list of the first n elements. Especially useful for lazy lists.list.drop(n) returns a list with the first n elements removed.list1 ::: list2 appends the two lists.list.reverse returns a list in the reverse order.list.splitAt(n) returns the tuple (list take n, list drop n).list1.zip(list2) returns a list of tuples, where the first element of the tuple is taken from list1 and the second from list2. The length of the result is the length of the shorter list.list.mkString(string) converts each element of the list into a string, and concatenates them with the string in between elements. listOfLists.flatten takes a list of lists of elements and returns a list of elements.list.map(function) returns a list in which the function of one argument has been applied to each element.listOfLists.flatMap(function) returns a list in which the function of one argument has been applied to each element of each sublist. Removes one “level” of nesting.list.filter(predicate) returns a list of the elements of the given list for which the predicate is true.list.partition(predicate) returns a tuple of two lists: a list of values that satisfy the predicate, and a list of those that do not.list.foldLeft(value)(_ function _) applies the function to each pair of elements of value::list, using each function result as the new first argument to the function, and returns the final value.(value /: list)(_ function _) is an alternate way of writing foldLeft.list.foldRight(value)(_ function _) applies the function to each pair of elements of the list with the value appended, starting from the right end of the list, using each function result as the new second argument to the function, and returns the final value.(list :\ value)(_ function _)is an alternate way of writing foldRight.list.find(predicate) returns, as Some(value), the first value in the list that satisfies the predicate, or None if no such value is found.list.takeWhile(predicate) returns a list of the values at the front of the given list that satisfy the predicate, stopping short of the first value that does not.list.dropWhile(predicate) returns a list omitting those values at the front of the given list that satisfy the predicate.list.span(predicate)returns the tuple (list takeWhile predicate, list dropWhile predicate).list.forall(predicate) checks if every element of the list satisfies the predicate.list.exists(predicate) checks if any element of the list satisfies the predicate.list.sortWith(comparisonFunction) sorts a list using the two-parameter comparison function. list.sortWith(_ < _)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.
if (condition) expressionif (condition) expression; else expressionif (condition) expression; else if (condition) expression; ...if (condition) expression; else if (condition) expression; ...; else expressionThe 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, ().
The for expression is used to create and return a list. The syntax is for (seq) yield expression, where:
seq is a semicolon-separated sequence of generators, definitions, and filters, beginning with a generator.
generator has the form variable <- list, where the list may be any expression resulting in a list.definition has the form variable = expression (the keywords var and val are not used here).filter has the form if condition.Examples:
for (v <- list) yield v returns a copy of list.for (v <- list) yield f(v) is equivalent to list map f.for (v <- list if p(v)) yield v is equivalent to list filter p.for (v <- lst; w = 2 * v; x <- lst; if x < w) yield (v, w, x)Syntax:
Thevariable match { case value1 => expression1 case value2 => expression2 ... case _ => expressionN }
match expression uses pattern matching to select a case, then the value of the match expression is the value of the corresponding expression. It is an error if there is no matching case; case _ will match anything.
Statements return the Unit value, ().
| Syntax | Example | Comments |
|---|---|---|
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. |
|
|
Zero or more else if clauses may be used, and the final else is optional. As in Java, braces should be used to group several statements into a single statement. |
while (condition) statement |
|
Nothing unusual to note. However, Scala has no break or continue statements. |
do { statements } while (condition) |
|
Nothing unusual to note. However, Scala has no break or continue statements. |
for (variable <- list) statement |
|
The parenthesized expression may contain tests, assignments, and additional generators (variable <- list expressions). |
for (variable <- min to max) statement |
|
to is a method of RichInt. to is inclusive; until excludes max. |
for (variable <- min to max if condition) |
for (i <- 1 to 15 if i % 2 == 0) print(i) |
for comprehensions may have guards. |
|
|
Cases are tried in order; the Types may be matched, as: |
Syntax:
override] [access] def methodName(arg: type, ..., arg: type) { body } // returns Unitoverride] [access] def methodName(arg: type, ..., arg: type): returnType = { body }access may be private, protected, or public by default.
The return type of a method can usually be omitted; it must be declared:
return statement.Any.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.
Syntax: (arg1: Type1, ..., argN:TypeN) => expression
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)
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.
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 { ... }AnyRef.class Foo(name: String) { constructor_body }class Foo(a: Int, var b: Int, val c: Int) { ... }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); ... }this, and can call the primary constructor.class Foo(a: Int, b: Int) extends Bar(a + b) { ... }class Dog(name: String) extends Animal with Friend { ... }with. Any uninitialized vars and vals defined by the trait must be initialized by the class.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 are declared like classes, used like Java interfaces, and may contain fully-defined methods.
val data = readline // Reads a single line from the Console
print(data) // Prints to the Console without a newline
println(data) // Prints to the Console with a newline
import scala.io.Source, scala.io.Source._
val chooser = new FileChooser
val result = chooser.showOpenDialog(null)
val file = if (result == FileChooser.Result.Approve) Some(chooser.selectedFile) else None
val fileName = Some(file)
for (line <- Source.fromFile(fileName).getLines) { dump(line) }
val lines = Source.fromFile(fileName).getLines.toList
Here is a template for a GUI program:
import scala.swing._
import event._
object SampleGUI extends SimpleGUIApplication {
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) |
listeners |
|
class TextField(text0 : java.lang.String, columns0 : Int) |
listeners |
|
class TextArea(text0 : java.lang.String, rows0 : Int, columns0 : Int) |
listeners |
text : java.lang.String |
class CheckBox(text : java.lang.String) |
listeners |
selected : Boolean |
class ButtonGroup(initialButtons : AbstractButton*) |
buttons : Set[AbstractButton] |
select (b : AbstractButton) : Unit |
class ComboBox[A](items : Seq[A]) |
listeners |
|
class MenuBar |
contents |
|
class Menu(title0 : java.lang.String) |
contents |
|
class MenuItem(title0 : java.lang.String) |
listeners |
|
| Panel/Layout | Example |
|---|---|
class BorderPanel |
|
class BoxPanel(orientation : Value) |
|
class FlowPanel(alignment : Value) |
|
class GridBagPanel |
|
class GridPanel(rows0 : Int, cols0 : Int) |
|
All Panels have: contents, listeners, reactions, contents, tooltip_=, listenTo, deafTo.
All LayoutContainers have add (comp : Component, c : Constraints) : Unit.