Uncategorized

Options

Options allow us to protect against NullPointerException exceptions.
Option[A] is a container for an optional value of type A. If the value of type A is present, the Option[A] is an instance of Some[A], containing the present value of type A. If the value is absent, the Option[A] is the object None.
For example:
def track(user: Option[User]) = match {
     case Some(u) => Tracker.track(u.id)
     case None => Tracker.track(GUEST)
}
More compact way:
Tracker.track(user map (_.id) getOrElse GUEST)
They can accept filters (conditions) as well:
def track(user: Option[User]) = match {
     case Some(u) if u.canTrack => Tracker.track(u.id)
     case _ => Tracker.track(GUEST)
}
More compact way:
Tracker.track(user filter (_.canTrack) map (_.id) getOrElse GUEST)
More robust:
def track(user: Option[User]) = match {
     case Some(u) if u.canTrack => Tracker.track(u.id)
     case None => Tracker.track(GUEST)
     case _ =>
}
More compact way:
if (user forall (_.canTrack))
     Tracker.track(user map (_.id) getOrElse GUEST)
Uncategorized

Control Abstraction

  • Reducing code duplication
    • higher-order functions are functions which take functions as parameters and are better for simplifying code
  • Currying
    • A curried function is applied to multiple argument lists, instead of just one:
      • eg. normal method: def normalSum(num1: Int, num2: Int) = num1 + num2
      • eg. curried method: def plainOldSum(x: Int, y: Int) = x + y What’s happening here is that when you invoke curriedSum, you actually get two traditional function invocations back to back. The first function invocation takes a single Int parameter named x, and returns a function value for the second function. This second function takes the Int parameter y
  • Writing new control structures
    • In languages with first-class functions, you can effectively make new control structures even though the syntax of the language is fixed. All you need to do is create methods that take functions as arguments
Uncategorized

Functions and Closures

  • Local functions: in Scala, you can define functions inside other functions. They will be inaccessible from outside the containing method. They can access the parameters of their enclosing functions
  • Function literals:
var increase = (x: Int) => x + 1
increase(10) //prints 11
  • foreach method takes a function as an argument and invokes that function on each of its elements:
val myList = List (1, 2, 3)
myList.foreach((x: Int) =>  (x))
  • filter method selects those elements of the collection that pass a test the user supplies:
val myList = List (1, 2, 3)
println(myList.filter((x: Int) => x > 2)) //prints 3
//or mix them with foreach:
myList.filter((x: Int) => x > 2).foreach((x: Int) => println(x)) //prints 3
  • One way to make function literals more brief, is to leave off the parameter types. This is called target typing because the targeted usage of an expression is allowed to influence the typing of that expression:
println(myList.filter((x) => x > 2)) // same as x => x > 2
  • Placeholder syntax: you can use underscores as placeholders for one or more parameters, as long as each parameter appears only one time within the function literal. Multiple underscores mean multiple parameters, not reuse of a single parameter repeatedly:
myList.filter(_ > 2)
  • Partially applied function: is an expression in which you don’t supply all of the arguments needed by the function. Instead, you supply some, or none of the needed arguments. You can replace an entire parameter list with an underscore:
//e.g.1:
myList.foreach((x: Int) => println(x)) //is same as:
myList.foreach(println _) //is same as:
myList.foreach(println)

//e.g.2:
def sum(a: Int, b:Int, c: Int) = a + b + c
val a = sum _
a(1, 2, 3) // 6
val b = sum(1, _ : Int, 3)
b(3) // 7
  • Closures: closures capture variables themselves, not the value to which the variables refer:
val more = 10
val addMore = (x: Int) => x + more //more is called a free variable, x is bounded variable
  • Special function call forms: Scala supports repeated parameters, named arguments, and default arguments:
    • Repeated parameters: Scala allows you to indicate last parameter of a function may be repeated:
def echo(args: String*) = 
    for(arg <- args) println (arg)

echo(“Hello”, “world”)

//you can pass an array of strings to this method this way:
val strArr = Array(“Hello”, “World”)
echo(strArr: _*) //this tells the compiler to pass each element of array as its own argument to echo, rather than all of it as one single argument
    • Named arguments: named arguments allow you to pass arguments to a function in a different order:
def speed(distance: Float, time: Float): Float = distance / time
speed(time = 10, distance = 100)
    • Default parameter values: Scala lets you specify default values for function parameters
def speed(distance: Float, time: Float = 50): Float = distance / time
speed(distance = 100) //2
  • Tail recursion: functions which call themselves as the last action, are called tail recursive. The Scala compiler detects tail recursion and replaces it with a jump back to the beginning of the function, after updating the function parameters with the new values. So, if the method is tail recursive, there won’t be any runtime overhead to be paid:
def approximate(guess: Double): Double = {
    if (isGoodEnough(guess)) guess
    else approximate(improve(guess))
Uncategorized

Built-in Control Structures

  • The only control structors in Scala are if, while, for, try, match, and function calls
  • if: val filename = if (args.nonEmpty) args(0) else “default_filename”
  • while loop: there are two types:
while (a != 0) {
    val temp = a
    a = b % a
    b = temp
}

do {
    line = readLine()
    println("Read: "+ line)
} while (line != "")
  • for loop: the for expression syntax works for any kind of collection, not just arrays. There are many ways to use a for loop:
//simple loop
val filesHere = (new java.io.File(".")).listFiles
for (file <- filesHere)
println(file)

//this adds filtering to the for loop
for (file <- filesHere if file.getName.endsWith(".scala"))
println(file)

//it’s possible to have multiple conditions
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)

grep(".*gcd.*")

//mid-steram variable bindings
def grep(pattern: String) =
    for {
        file <- filesHere
        if file.getName.endsWith(".scala")
        line <- fileLines(file)
        trimmed = line.trim
        if trimmed.matches(pattern)
    } println(file +": "+ trimmed)

grep(".*gcd.*")

//producing a new collection
/*this will assemble a collection of Scala files. The type of the 
resulting collection is based on the kind of collections 
processed in the iteration clauses. In this case the result is an 
Array[File], because filesHere is an array and the type of the yielded 
expression is File.*/

def scalaFiles =
    for (
        file <- filesHere
        if file.getName.endsWith(“.scala”)
    ) yield file
  • throwing exceptions: e.g. throw new RuntimeException(“n must be even”). In this example, one branch of an if computes a value, while the other throws an exception and computes Nothing. The type of the whole if expression is then the type of that branch which does compute something.
  • try/catch expressions: example:
try {
    val f = new FileReader(“filename.txt”)
} catch {
    catch ex: FileNotFoundException =>
    catch ex: IOException =>
}
  • finally clause: you can wrap an expression in a finally clause if you want to cause some code to execute no matter how the expression terminates. e.g.:
val f = new FileReader(“input.txt)
    try {
        //something
    } finally {
        f.close()
}
  • match expression: is like switch statement. The default is specified using an underscore (_). There’s no break keyword, as there is no fall through from one alternative to the next. Big difference to Java/PHP, is that match results in a value e.g.:
val input = args(0)
    input match {
        case “salt” => println(“pepper”)
        case _ => println(“type salt!”)
    }

//Same as:

val result = input match {
    case “salt” => “pepper"
    case _ => println(“type salt!”)
}

println (result)
Uncategorized

Functional Objects

  • If a class doesn’t have body, you don’t need to have curly brackets
  • The Scala compiler will compile any code you place in the class body, which isn’t part of a field or a method definition, into the primary constructor. For example, you could print a debug message like this:
class Rational(n: Int, d: Int) {
     println("Created "+ n +"/"+ d)
}
  • The override modifier in front of a method definition signals that a previous method definition is overridden
  • A precondition is a constraint on values passed into a method or constructor, a requirement which callers must fulfil. One way to do that is to use require:
class Rational(n: Int, d: Int) {
    require(d != 0)
    override def toString = n +"/"+ d
}
  • Sometimes you need multiple constructors in a class. In Scala, constructors other than the primary constructor are called auxiliary constructors. Auxiliary constructors in Scala start with def this(…). In Scala, every auxiliary constructor must invoke another constructor of the same class as its first action. In other words, the first statement in every auxiliary constructor in every Scala class will have the form “this(…)”. The invoked constructor is either the primary constructor or another auxiliary constructor that comes textually before the calling constructor. The net effect of this rule is that every constructor invocation in Scala will end up eventually calling the primary constructor of the class. The primary constructor is thus the single point of entry of a class.
Uncategorized

Basic Types and Operations

  • Byte, Short, Int, Long, Char = integral types; + Float, Double = numeric types
  • Raw strings are represented with three double quotation marks. Raw strings can contain quotation marks, new lines, etc. eg.
println("""something which has "quotation" 
and spans multiple lines""")
  • Use Strip Margin method to remove empty spaces above:
println("""|the pipe strings
|will appear in same column""".stripMargin)
  • Operators are methods!
  • Infix operator notation means the method to invoke sits between the object and the parameter or parameters you wish to pass to method, e.g. 7 + 2 or s indexOf ‘a’
  • Prefix notation is when you put method name before the object on which you are invoking the method, e.g. the ‘-‘ in -7
  • Postfix notation is when you put the method after the object, for example the “toLong” in “7 toLong
  • Prefix and postfix are unary: they take just one operand, unlike infix
  • You can leave off empty parentheses on method calls, e.g. s.toLowerCase (which in turn can be written as s toLowerCase using postfix operator notation). By convention, you include parentheses if the method has side effects, e.g. println()
Uncategorized

SBT

  • To create a SBT project, place source files in src/main/scala and add a build.sbt to root folder:
lazy val root = (project in file(“.”)).
    settings(
        name := “Project Name”,
        version := “1.0”,
        scalaVersion := “2.10.3"
    )
  • To run (or compile) continuously, run sbt then ~run (or ~compile or ~test)