I usually write notes when I am studying or learning new skills, when I was in University my classmates copied my notes to help them with their learning. That is why I am sharing my notes maybe it will help you.
Scala Basics
Scala “scalable language” runs on the Java VM and interoperates with all Java libraries. You can use Scala for writing scripts or for building large systems and frameworks. Scala is a blend of object orient and functional programming concepts. Scala’s functional programming constructs make it easy to build logic quickly from simple parts while its object-oriented constructs make it easy to structure large system and adapt them to new requirements.
Functional programming is guided by two main ideas:
- Functions are first class values. This means a function is a value same as integer or string. A function can passed as an argument to another function, returned as a result from a function.
-
Operations of should map input values to output values rather than change data in place. This means methods should not have side effects. All data types and objects should be immutable.
Setting Up Scala Development Environment
Figure 1: Where to download scala
Best way to learn is by writing some code. In this section, we will go through a quick tutorial of Scala basics. To run the code samples, you should have standard Scala installation. You can get it from http://www.scala-lang.org. You can also use a Scala plug-in for Eclipse, IntelliJ or NetBeans.
Scala Interpreter
Figure 2: Scala Shell Interpreter
Scala comes with an interactive “shell” for writing Scala expressions and programs. The interpreter will evaluate expression you type and print the resulting value.
scala> 567*8+20
res0: Int = 4556
Scala Variables
Scala has two kinds of variables:
- val: is similar to final variable in Java or readonly in C#. once initialized it can never be reassigned.
scala> val str = “This is a book about Scala”
str: String = This is a book about Scala
scala> str = “change this string”
<console>:12: error: reassignment to val
str = “change this string”
- var: is similar to a non-final or non readonly variable in Java and C# respectively.
scala> var m = “This is a book about Scala”
m: String = This is a book about Scala
scala> m = “Change this string”
m: String = Change this string
Notice that in both examples, I did not define the type. Scala’s ability to infer types makes the code less cluttered with unnecessary explicit type annotations. Though an explicit type annotation can both ensure the Scala compiler infer the type you intend as well as serve as a useful documentation for the readers of the code. In Scala, you specify a variable type after is name separated by a colon.
scala> val s:String = “Hello Scala Book”
s: String = Hello Scala Book
Scala Functions
scala> def max(x:Int, y: Int): Int = {
| if(x > y) x
| else y
| }
max: (x: Int, y: Int)Int
scala> max(99,767)
res2: Int = 767
Functions definitions starts with “def”, followed by the function’s name, followed by comma-separated list of parameters in parentheses. A type annotation must follow each parameter, because Scala does not infer function parameter types. After the close parenthesis another type annotation that defines the result type of the function. You can leave the result type and Scala will infer it.
while and if constructs
var i = 0
i: Int = 0
scala> while(i < 20){
| if(i >0) println(i)
| i += 1
| }
1
2
…
19
While (condition) statement
The while will execute the statement or block of statements (complex statement) contained within “{}” as long as the condition is true.
If(condition) statement1 else statement2
If will execute statement1 if the condition is true. If there is an else then statement2 will get executed if the condition is false.
Arrays
scala> val big = new java.math.BigInteger(“3728”)
big: java.math.BigInteger = 3728
scala> val g = new Array[String](5)
g: Array[String] = Array(null, null, null, null, null)
scala> g(0) = “Hi”
scala> g(1) = ” ”
scala> g(2) = ” Scala”
scala> g(3) = ” Says Functional”
scala> g(4) = ” is the way to go”
You instantiate objects using the “new” keyword. You can configure the object instance when you create it. For example as shown in the code above val big with instantiated with BigInteger with value of 3728. And g was created as an array of type string with 5 elements.
Since functions are first class constructs in Scala, you can pass the function literal that takes parameter to another function. If the function literal takes a single parameter, you need not name specify the argument.
scala> g.foreach(print)
Hi Scala Says Functional is the way to go
apply & update methods
In Scala, when you apply parentheses surrounding one or more values to a variable, Scala will transform the code into an invocation of a method named apply on that variable. So g(0) is transformed to g.apply(0). Any application of an object to some arguments in parentheses will be transformed to an apply method call. This will compile only if the type of the object defines an apply method. When an assignment is made to a variable to which parentheses and one or more arguments have been applies Scala will transform that into an invocation of an update method that takes the arguments in parentheses. So g(0) = “hello” will be transformed into g.update(0,”Hello”)
Lists
Scala array is a mutable sequence of objects that all share the same type. And Array[String] contains only string. Although you can’t change the length on an array after is instantiated. You can change its elements values. For an immutable sequence of objects that share the same type you can use Scala’s List class. List[String] can contain only strings.
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b = List(7,8,3)
b: List[Int] = List(7, 8, 3)
scala> val ab = a ::: b
ab: List[Int] = List(1, 2, 3, 7, 8, 3)
scala> val s = 1::b
s: List[Int] = List(1, 7, 8, 3)
The code above establishes a new val named a initialized with a new List[Int] with values 1,2, and 3. Note that List.apply() is defined as a factory method in Scala. When you call a method on a List that might mutate the list, it will creates and returns a new list with the new value. For example the ::: method is for list concatenation.
scala> val k = 1 :: 2 :: 8 :: 9 :: Nil
k: List[Int] = List(1, 2, 8, 9)
Note, the method :: is method on its right operand in Scala, this issue will be discussed in more detail later.
Tuples
Tuple are a useful object contain. Tuples are immutable and contain different types of elements. Tuples are similar to C language struct construct. Though you do define the tuple structure in advance. Typically you use tuples when you need to return multiple objects from a method.
scala> val complexTuple = (78,”Rony”, “Alicante”, “Spain”)
complexTuple: (Int, String, String, String) = (78,Rony,Alicante,Spain)
scala> println(complexTuple._1)
78
scala> println(complexTuple._3)
Alicante
Once you have a tuple instantiated, you can access its elements individually with a dot, underscore, and the one-based index of the element, as shown in the example above.
Sets and Maps
Scala provides mutable and immutable alternatives for sets and maps, both use the same simple names but they are in different packages or namespaces. The default is the immutable set as shown in the listing below. The ‘+=’ operation returns a new set that is why the operation succeeds with var and fails with val.
scala> var set1 = Set(“Alicante”,”Granada”)
set1: scala.collection.immutable.Set[String] = Set(Alicante, Granada)
scala> var set2 = set1
set2: scala.collection.immutable.Set[String] = Set(Alicante, Granada)
scala> set2 += “Barcelona”
scala> set1
res20: scala.collection.immutable.Set[String] = Set(Alicante, Granada)
scala> set2
res21: scala.collection.immutable.Set[String] = Set(Alicante, Granada, Barceolona)
scala> val set3 = set1
set3: scala.collection.immutable.Set[String] = Set(Alicante, Granada)
scala> set3 += “Barcelona”
<console>:13: error: value += is not a member of scala.collection.immutable.Set[String]
Expression does not convert to assignment because receiver is not assignable.
set3 += “Barcelona”
to use the mutable version you import the scala.collection.mutable package as shown in the listing below
scala> import scala.collection.mutable
import scala.collection.mutable
scala> val mutableset = mutable.Set(“Alicante”,”Granada”)
mutableset: scala.collection.mutable.Set[String] = Set(Alicante, Granada)
scala> mutableset += “Barceolona”
res24: mutableset.type = Set(Alicante, Barceolona, Granada)
Now the ‘+=’ operator works with ‘val’ as the set is modified. The listing below shows similar operations for Map. To create a mutable Map use scala.collection.mutable package Map class implementation. The default Map uses the immutable implementation.
scala> val areaCode = mutable.Map[Int,String]()
areaCode: scala.collection.mutable.Map[Int,String] = Map()
scala> areaCode += (416-> “Toronto”)
res25: areaCode.type = Map(416 -> Toronto)
scala> areaCode += (905-> “GTA”)
res26: areaCode.type = Map(905 -> GTA, 416 -> Toronto)
scala> areaCode += (613-> “Calgary”)
res27: areaCode.type = Map(905 -> GTA, 613 -> Calgary, 416 -> Toronto)
scala> val stars = Map( 1->”*”,2->”**”,3->”***”,4->”****”,5->”*****”)
stars: scala.collection.immutable.Map[Int,String] = Map(5 -> *****, 1 -> *, 2 -> **, 3 -> ***, 4 -> ****)
scala> println(stars(3))
***
Semicolon Inference
In Scala, a semicolon at the end of a statement is usually optional. You can type one if you want but you do not have to if the statement appears by itself on a single line. On the other hand, a semicolon is required if you write multiple statements on a single line:
scala> val s = “Moustafa”; println(s)
scala> if (x <2)
| println(“too small”) else
| println(“Ok”)
Control Structures
Scala has the following control structures:
- if: if works like in Java and C#, it tests a condition and then executes one of two code branches depending on whether the condition holds true.
scala> var args:Array[String] = Array()
args: Array[String] = Array()
scala> val fileName = if(!args.isEmpty) args(0) else “default.txt”
fileName: String = default.txt
- while: Just like in C# and Java while has a conditions and a body. The body is executed over and over again as long as the condition holds true.
scala> var a = 20
a: Int = 20
scala> var b = 30 ;
b: Int = 30
scala> while (a != 0) { val temp = a
| a = b% a
| b = temp
| }
scala> b
res1: Int = 10
another form of the while loop is the do-while where the code block is executed at least once and keeps on executing as long as the while condition is true
do {
| line = readLine()
| println(” Read: “+ line)
| } while (line !=””)
-
for: Scala’s for expression lets you combine a few simple ingredients in different ways to express a wide variety of iterations.
- Iteration through collections
val filesHere = (new java.io.File(“.”)).listFiles
for(file <- filesHere) println(file)
for ( i<- 1 to 4) prinrln(“Iterntion “+i)
- Filtering
val filesHere = (new java.io.File(“.”)).listFiles
for(file <- filesHere
if file.isFile
if file.getName.endsWith(“.scala”)) println(file)
- Nested Iteration
def fileLines(file: java.io.File) =
scala.io.Source.fromFile(file).getLines().toList
def grep(pattern: String) =
for (
file <- filesHere
if file.getName.endsWith(".scala");
line <- fileLines(file)
if line.trim.matches(pattern)
) println(file + ": " + line.trim)
-
Mid-stream variable bindings same as example above
- Producing a new collection
val filesHere = (new java.io.File(“.”)).listFiles
val forLineLengths =
for {
file <- filesHere
if file.getName.endsWith(“.scala”)
line <- fileLines(file)
trimmed = line.trim
if trimmed.matches(“.*for.*”)
} yield trimmed.length
To generate a new value for each iteration in a for expression prefix the for expression body by the keyword ‘yield’. As in the example above each time the body of the for expression executes it produces one value in this case the length of the trimmed line.
- Try: this issued for handling exceptions.
def throws1 {
throw new IllegalArgumentException
}
def throws3 {
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
try {
val f = new FileReader(“input.txt”)
// Use and close file
println(“f [” + f + “]”)
} catch {
case ex: FileNotFoundException => // Handle missing file
println(“ex [” + ex + “]”)
case ex: IOException => // Handle other I/O error
println(“ex [” + ex + “]”)
}
finally {
file.close() // Be sure to close the file
}
}
- Match: Scala match expression is similar to C# and Java switch statement. With default case si specified with an underscore (_) and there is no flow from case to case so no need for a break statement
def match2(args: Array[String]) {
val firstArg = if (!args.isEmpty) args(0) else ""
val friend =
firstArg match {
case "salt" => "pepper"
case "chips" => "salsa"
case "eggs" => "bacon"
case _ => "huh?"
}
println(friend)
}
- function calls.
Almost all of Scala’s control structures result in some value even try expressions
def urlFor(path: String) =
try {
new URL(path)
} catch {
case e: MalformedURLException =>
new URL("http://www.scala-lang.org")
}
Scala does not have break and continue because they do not mesh well with functional literals.