Scala concepts

The following notes are taken after reading “Programming in Scala second edition”,
by Martin Oderdky, Lex Spoon and Bill Venners.

Valid operator characters

Scala syntax allows method names to use special characters such as +, * and :, and 
to use them as infix operators, which effectively allows operator overloading.


The colon operator character

operators that end in : are right associative and the invoking object appears on 
the right side of the operator. 


val newList3 = 4 :: myList // :: is a function on the myList object


val vs var vs def

val = immutable value var = mutable value def = function returning a value

Arrays

//create array
var myArray = new Array[String](3)


//Use () instead of []
myArray(0) = "test"
//the above command is the same as:
myArray.update(0,"test")


Lists

//create array
var myArray = new Array[String](3)


//Use () instead of []
myArray(0) = "test"
//the above command is the same as:
myArray.update(0,"test")


//Create list:
val myList = List(1,2,3)
//or
val myList2 = 1::2::3::Nil


//Add item to head of list
val newList3 = 4 :: myList


//Add item to the end of a list
val newList4 = myList :+ 4


//Concat two lists
val newList5 = myList:::myList2


//Use head for first element and tail for the remaining
newList5.head
newList5.tail

Tuples

val things = ("a", 1, 3.5)
println(things._1)
println(things._2)
println(things._3)


Require

class Rational(n: Int, d:Int){
 require(d!=0)
  override def toString = n + "/" + d
}


Constructors

// the primary constructor is in the body of the class, and the parameters 
// comes right after the class name 
class Greeter(message: String) {
  println("A greeter is being instantiated")


  def SayHi() = println(message)
}


val greeter = new Greeter("Hello world!")


// a auxiliarycan be created also 
class Greeter2(message: String, secondaryMessage: String) {
  def this(message: String) = this(message, "")


  def SayHi() = println(message + secondaryMessage)
}


val greeter2 = new Greeter2("Hello world!")


Singleton

//singleton
object CashRegister {
  def open { println("opened") }
  def close { println("closed") }
}

Companion object

class IntPair(val x: Int, val y: Int)
object IntPair {
  import math.Ordering
  implicit def ipord: Ordering[IntPair] =
    Ordering.by(ip => (ip.x, ip.y))
}


Implicit conversion

// for the example: create a class that represents a complex number
class Complex(val real : Double, val imag : Double) {
  def +(that: Complex) = new Complex(this.real + that.real, this.imag + that.imag)
  def -(that: Complex) = new Complex(this.real - that.real, this.imag - that.imag)
  override def toString = real + " + " + imag + "i"
}


// create the implicit conversion
// with this object you can convert a Double object to a Complex object
object ComplexImplicits {
  implicit def Double2Complex(value : Double) =
    new Complex(value,0.0)
}


// import the implicit
import ComplexImplicits._


val myComplexNumber = new Complex(3,4)
// here the double is converted
val sum = 8.5 + myComplexNumber


## If statement returns a value


val a = 2
val b = 3
val x = if (a > b) a else b


for expressions en yield

val nums = Seq(1,2,3)
val letters = Seq('a', 'b', 'c')


// multiple generators
val res = for {
  n <- nums
  c <- letters
} yield (n, c)


// for expression with generators and filters
val authorsWhoHaveWrittenAtLeastTwoBooksV1 = for {
  b1 <- books       //gen
  b2 <- books       //gen
  if b1 != b2       //filter
  a1 <- b1.authors  //gen
  a2 <- b2.authors  //gen
  if a1 == a2       //filter
} yield a1
println("nAuthors who have written at least two books:")
authorsWhoHaveWrittenAtLeastTwoBooksV1.foreach(println)


// for expression with a generator, a definition and a filter
 for {
    p

Match Expressions

// simple match
def toYesOrNo(choice: Int): String = choice match {
  case 1 => "yes"
  case 0 => "no"
  case _ => "error"
}


// more complex match
def eval(expression : Expression, xValue : Int) : Int = expression match {
  case X() => xValue
  case Const(cst) => cst
  case Add(left, right) => eval(left, xValue) + eval(right, xValue)
  case Mult(left, right) => eval(left, xValue) * eval(right, xValue)
  case Neg(expr) => - eval(expr, xValue)
}


Local functions

// It is possible to create a function (process) in another function (filter)
object FilterTest extends Application {
  def filter(xs: List[Int], threshold: Int) = {
    def process(ys: List[Int]): List[Int] =
      if (ys.isEmpty) ys
      else if (ys.head < threshold) ys.head :: process(ys.tail)
      else process(ys.tail)
    process(xs)
  }
  println(filter(List(1, 9, 2, 8, 3, 7, 4), 5))
}


First class functions

def plusOne(x : Int) = x + 1
val func : Int => Int = plusOne
println(func(1))




Placeholder syntax

// use can use the _ as a placeholder for one or more parameters
someNumbers.filter(_>0)


Closure

// A closure is a function, whose return value depends on the value of one or 
// more variables declared outside this function.
var factor = 3
val multiplier = (i:Int) => i * factor
println( "2 x 3 = " +  multiplier(2) )
factor = 4
println( "2 x 4 = " +  multiplier(2) )


Repeated Parameters

// use a * for a repeated parameter
def printStrings( args:String* ) = {
 var i : Int = 0;


 for( arg

Named arguments

def printName(first:String = "John", last:String = "Smith") = {
 println(first + " " + last)
}
printName(last = "Jones")


Tail recursion

When you enter the recursion as the last step of a function, the stack is reused.


Currying

// Methods may define multiple parameter lists. When a method is called with a fewer
// number of parameter lists, then this will yield a function taking the missing
// parameter lists as its arguments.
def add(x:Int)(y:Int) = x + y
add(1)(2)   // 3
add(7)(3)   // 10


By name parameter

// The :=> indicates that the argument is not evaluated at the point of function
// application, but instead is evaluated at each use within the function. That is,
// the argument is evaluated using call-by-name.


def time() = {
 println("Entered time() ...")
 System.nanoTime
}


// uses a by-name parameter here
def exec(t: => Long) = {
 println("Entered exec, calling t ...")
 println("t = " + t)
 println("Calling t again ...")
 t
}


println(exec(time()))


Calling parent constructors

// (1) primary constructor
class Animal (var name: String, var age: Int) {
 // (2) auxiliary constructor
 def this (name: String) {
   this(name, 0)
 }
 override def toString = s"$name is $age years old"
}


// calls the Animal one-arg constructor
class Dog (name: String) extends Animal (name) {
 println("Dog constructor called")
}
new Dog("elvis")


Any class

All classes have Any as superclass


Null

Null is a trait, which (if you’re not familiar with traits) is sort of like an
abstract class in Java. There exists exactly one instance of Null, and that is null


Nothing

Nothing is - together with Null - at the bottom of Scala's type hierarchy.


Nothing is a subtype of every other type (including Null); there exist no instances
of this type. Although type Nothing is uninhabited, it is nevertheless useful in
several ways. For instance, the Scala library defines a value
scala.collection.immutable.Nil of type List[Nothing]. Because lists are covariant in
Scala, this makes scala.collection.immutable.Nil an instance of List[T], for any
element of type T.


Trait that extends a class

When a trait extends a class, then only classes from that type may mixin this trait


Imports in a function

//You can import within a function
def printRandom {
 {
   import scala.util.Random
   val r1 = new Random   // this works
 }
 val r2 = new Random     // error: not found: type Random
}


Imports with renames

// with the following import, you can use the java map as Jmap
import java.util.{Map ⇒ JMap, List ⇒ JList}


Package objects

// Package Objects in Scala was introduced as part of Scala 2.8. With this feature a 
// package in scala can contain field declarations, methods along with the classes,
// objects and traits. The methods and variable declarations are put into the package
// object and are accessible in the package for which the package object was declared.
//File: TestClass.scala
package net{
 package javabeat{
   class TestClass{
     def instanceMethod():String = {
       println("From TestClass: "+packageMethod1)
       "Invoked instance method"
     }
   }


   object TestClass extends App{
     val testObj = new TestClass
     println(testObj.instanceMethod)
     println(packageMethod1)
     println(packageField1)
   }
 }
}


package net{
 package object javabeat{
   def packageMethod1():String = {
     "Invoked Package Method1"
   }
   val packageField1 = "Package Field1"
 }
}


Sealed classes

// A sealed class may not be directly inherited, except if the inheriting
// template is defined in the same source file as the inherited class.
// However, subclasses of a sealed class can inherited anywhere.


abstract class LogMessage
case class StringMessage(message:String) extends LogMessage
case class ExceptionMessage(exception:Throwable) extends LogMessage
case class BothMessage(message:String, exception:Throwable) extends LogMessage


class Logger {
 def debug(l:LogMessage) = log(10,l)
 def info(l:LogMessage) = log(5,l)
 def error(l:LogMessage) = log(1,l)


 def log(level:Int, l:LogMessage):Unit = l match  {
   case StringMessage(msg) => println(msg)
   case ExceptionMessage(exception:Error) => exception.printStackTrace
   case ExceptionMessage(ex) => println(ex.toString)
 }
}


Lazy val

// The difference between them is, that a val is executed when it is
// defined whereas a lazy val is executed when it is accessed the first time.


val normalVal={
 println("----   Initializing normal val    ----");
 "This is the normal val"
}
lazy val lazyVal = {
 println("----   Initializing lazy val   ----");
 "This is the lazy val"
}
println ("nnno references have been made yetnn")
println ("Accessing normal val : ")


Enums

object Margin extends Enumeration {
 type Margin = Value
 val TOP, BOTTOM, LEFT, RIGHT = Value
}


XML