Introduction to Scala

logo

Introduction to
                     __                                               
     ________ ___   / /  ___  
    / __/ __// _ | / /  / _ | 
  __\ \/ /__/ __ |/ /__/ __ | 
 /____/\___/_/ |_/____/_/ | | 
                          |/  Programming Language

Saleem Ansari (@tuxdna)

http://tuxdna.in/

Presenter Notes

Outline

Basics

Functional Programming in Scala

Object Oriented Programming in Scala

Question/Answer

Presenter Notes

JVM Languages

JVM Languages

Presenter Notes

Basic introduction

  • What is Scala?
  • Scala tools
  • Basic Data Types
  • Collections
  • if-else, loops, case-match, exception handling

Presenter Notes

What is Scala?

Scala stands for "scalable language" -- designed to grow with demands of its users.

What makes Scala a "scalable language"?

  • Scala is: compiled, statically typed, strictly typed, type inferred, concise, expressive, pleasant to use, and high level
  • Scala is: Object Oriented, Functional and Imperative, runs on JVM, compatible with Java

Compare it to other languages such as Python, Ruby etc., which are interpretted, dynamically typed and so on.

Presenter Notes

Scala Tools

  • scala -- The Scala Interperter ( think of java )
  • scalac -- The Scala Compiler ( think of javac )
  • sbt -- Scala Build Tool ( think of Ant, Ivy, Maven etc. )
  • ScalaIDE -- Eclipse IDE with Scala plugins
  • Other IDE also support Scala ( IntelliJ, Netbeans etc. )

Scala REPL - Read Eval Print Loop

1 $ scala
2 Welcome to Scala version 2.9.1 (OpenJDK 64-Bit Server VM, Java 1.7.0_51).
3 Type in expressions to have them evaluated.
4 Type :help for more information.
5 
6 scala> println("Hello Scala World!")
7 Hello Scala World!
8 
9 scala>

Presenter Notes

Data Types

Data Types: ( all integers are signed two's complement )

  • Integers: Byte (8bit), Short (16bit), Int (32bit), Long (64bit)
  • Char (16 bit unicode character), String (squence of Chars)
  • Reals: Float (32bit), Double (64bit)
  • Boolean: either true or false

Literals

  • Basic data types: 1, 0.123, 12L, 'a', "String"
  • Symbol literal: 'identifier

Presenter Notes

Values / Variables

 1 scala> val x = 10
 2 x: Int = 10
 3 scala> x = 12
 4 <console>:8: error: reassignment to val
 5        x = 12
 6          ^
 7 
 8 scala> var y = 10
 9 y: Int = 10
10 scala> y = 12
11 y: Int = 12

Presenter Notes

Type Hierarchy

class hierarchy

Presenter Notes

Collections

In addition to Java collections Scala provides:

  • List ( similar to java.util.LinkedList )
  • Array ( similar to Java Array )
  • Set ( similar to java.util.Set )
  • Map ( similar to java.util.Map )
  • Tuple ( Java doesn't have a Tuple )
  • Immutable collections ( scala.collection.immutable )
  • Mutable collections ( scala.collection.mutable )

Immutability: a collection once create can not be changed in itself, however we can compose a collection from other collections. Such collections have big benefits:

  • no locks to be acquired
  • support concurrent operations

Presenter Notes

Collections Hierarchy

Scala Collections

Presenter Notes

List / Array

many elements

array elements

1 scala> val lst = List(1,2,3,4,5,6,7,8,10)
2 lst: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 10)
3 
4 scala> val arr = Array(1,2,3,4,5,6,7,8,9,10)
5 arr: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Presenter Notes

Map

map

1 scala> val radiation = Map('a' -> "alpha", 'o' -> "omega", 
2                            'g' -> "gamma")
3 scala> radiation('g')
4 res5: String = gamma

Presenter Notes

Set

set

1 scala> val T = Set("casey", "drew", "jade")
2 scala> val V = Set("drew", "jade", "glen")
3 scala> val S = Set("alex", "hunter", "casey", "drew")
4 scala> val U = V union T union S union 
5                  Set("blair", "erin", "francis", "era")
6 scala> val commonSet = S & T & V
7 commonSet : scala.collection.immutable.Set[String] = Set(drew)

Presenter Notes

Tuple

 1 scala> val tuple1 = Tuple1(1)
 2 tuple1: (Int,) = (1,)
 3 
 4 scala> val tuple2 = ('a', 1)
 5 tuple2: (Char, Int) = (a,1)
 6 
 7 scala> val tuple3 = ('a', 1, "name")
 8 tuple3: (Char, Int, java.lang.String) = (a,1,name)
 9 
10 scala> tuple1._1
11 res0: Int = 1
12 scala> tuple2._2
13 res1: Int = 1
14 scala> tuple3._1
15 res2: Char = a
16 scala> tuple3._3
17 res3: String = name

Presenter Notes

Basic program constructs

  • if-else expression
  • loops: for comprehension
  • pattern matching
  • exception handling

Presenter Notes

If-Else branching

 1 scala> import java.util.Calendar
 2 import java.util.Calendar
 3 
 4 scala> val now = Calendar.getInstance()
 5 now: java.util.Calendar = java.util.GregorianCalendar[....]
 6 
 7 scala> val hour = now.get(Calendar.HOUR_OF_DAY)
 8 hour: Int = 19
 9 
10 scala> println( if(hour < 12) "good afternoon" else "good morning")
11 good morning

Presenter Notes

Loops

 1 scala> val numbers = (1 to 10) toList
 2 numbers: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 3 
 4 scala> for(n <- numbers) print(n + " ")
 5 1 2 3 4 5 6 7 8 9 10
 6 
 7 scala> var index = 0
 8 index: Int = 0
 9 
10 scala> while(index < numbers.length) { 
11          print(numbers(index) + " "); index += 1
12        }
13 1 2 3 4 5 6 7 8 9 10
14 
15 scala> var index = 0
16 scala> do {
17          print(numbers(index) + " ")
18          index += 1
19        } while (index < numbers.length)
20 1 2 3 4 5 6 7 8 9 10

Presenter Notes

Pattern matching

 1 scala> val dow = now.get(Calendar.DAY_OF_WEEK)
 2 dow: Int = 3
 3 
 4 scala> dow match {
 5         case 1 => "Sunday"
 6         case 2 => "Monday"
 7         case 3 => "Tuesday"
 8         case 4 => "Wednesday"
 9         case 5 => "Thursday"
10         case 6 => "Friday"
11         case 7 => "Saturday"
12       }
13 res20: java.lang.String = Tuesday
14 
15 scala> dow match {
16         case x if x == 1  || x == 7 => "Weekend"
17         case _ => "Workday"
18       }
19 res21: java.lang.String = Workday

Presenter Notes

Pattern matching contd...

 1 val text =
 2  """|Hello Scala World
 3     |Scala is a wonderful language
 4     |OO + FP make Scala wonderful
 5     |You should also try Scala""".stripMargin('|')
 6 
 7 val nextToScala = """.*\bScala (\w+).*""".r
 8 > nextToScala  : scala.util.matching.Regex = .*\bScala (\w+).*
 9 
10 for (line <- text.split("\n")) yield line match {
11   case nextToScala(w) => w
12   case _ => ""
13 }
14 > res0: Array[String] = Array(World, is, wonderful, "")

Presenter Notes

Exception handling

 1 scala> var divisor = 0
 2 divisor: Int = 0
 3 
 4 scala> def divide(n: Int) = 1 / divisor
 5 divide: (n: Int)Int
 6 
 7 scala> def divide(n: Int) = n / divisor
 8 divide: (n: Int)Int
 9 
10 scala> try { divide(10) } catch {
11          case e: ArithmeticException => "Check your calculations!" 
12        }
13 res34: Any = Check your calculations!
14 
15 scala> divisor = 2
16 divisor: Int = 2
17 
18 scala> try { divide(10) } catch {
19          case e: ArithmeticException => "Check your calculations!"
20        }
21 res35: Any = 5

Presenter Notes

Functional Programming

Lambda calculus: (closure, functions and values, higher order functions, recursion)

lambda

  • First-class and higher-order functions
  • Pure functions
  • Recursion
  • Strict versus non-strict evaluation
  • Type systems

Presenter Notes

Defining functions

map/filter

1 scala> def f(x: Double) = x * x
2 f: (x: Double)Double
3 
4 scala> def g(y: Double) = 1 / y
5 g: (y: Double)Double

Presenter Notes

Composing functions

1 scala> def gof(x: Double) = g(f(x))
2 gof: (x: Double)Double
3 
4 scala> gof(2)
5 res42: Double = 0.25
6 
7 scala> gof(4)
8 res43: Double = 0.0625

g(f(x))

Presenter Notes

Hallmarks of Functional Programming

Hallmarks of Functional Programming

  • mapping
  • filtering
  • folding
  • reducing

Presenter Notes

Map and Filter

 1 val lst = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
 2 lst.map(x => x * x)
 3 > res0: List[Int] = List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)
 4 
 5 lst.filter(x => x % 3 == 0)
 6 > res1: List[Int] = List(3, 6, 9)
 7 
 8 lst.reduce((x, y) => x + y)
 9 > res2: Int = 55
10 
11 lst.fold(0)((x, y) => x + y)
12 > res3: Int = 55

Presenter Notes

Fold / Reduce

 1 lst.reduce((x, y) => x * y)
 2 > res4: Int = 3628800
 3 
 4 lst.fold(1)((x, y) => x * y)
 5 > res5: Int = 3628800
 6 
 7 lst.reduceLeft((x, y) => x * y)
 8 > res6: Int = 3628800
 9 
10 lst.foldLeft(1)((x, y) => x * y)
11 > res7: Int = 3628800
12 
13 lst.reduceRight((x, y) => x * y)
14 > res8: Int = 3628800
15 
16 lst.foldRight(1)((x, y) => x * y)
17 > res9: Int = 3628800

Presenter Notes

Map Shuffle Reduce

1 val result = (1 to 20)
2     .map(x => x * x)
3     .groupBy(_ % 5).par
4     .map { y => y._2.sum }
5     .sum
6 > result  : Int = 2870

Presenter Notes

First class function

A function is treated same as any other variable. Which means we can store a function in a variable. According to Wikipedia:

  • such a language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.
  • Some programming language theorists require support for anonymous functions as well.
  • In languages with first-class functions, the names of functions do not have any special status; they are treated like ordinary variables with a function type.

Presenter Notes

First class function

Example:

 1 def add(a: Int, b: Int) = a + b
 2 > add: (a: Int, b: Int)Int
 3 val myfunc = (a: Int, b: Int) => a + b
 4 > myfunc  : (Int, Int) => Int = <function2>
 5 val otherfunc = add _
 6 > otherfunc  : (Int, Int) => Int = <function2>
 7 
 8 add(2, 4) // > res0: Int = 6
 9 myfunc(4, 5) // > res1: Int = 9
10 otherfunc(6, 7) // > res2: Int = 13
11 
12 (x: Int, y: Int, z: Int) => x * y * z
13 > res3: (Int, Int, Int) => Int = <function3>
14 
15 ((x: Int, y: Int, z: Int) => x * y * z)(5,4,3)
16 > res4: Int = 60

Presenter Notes

Higher Order Function

In mathematics and computer science, a higher-order function (also functional form, functional or functor) is a function that does at least one of the following:

  • takes one or more functions as an input
  • outputs a function

Presenter Notes

Higher Order Function examples

 1 scala> def transform(fn: (Int) => Int, number: Int) = fn(number)
 2 transform: (transformer: Int => Int, number: Int)Int
 3 
 4 scala> val plus5 = transform( (x: Int) => x + 5, _: Int)
 5 plus5: Int => Int = <function1>
 6 
 7 scala> val into3 = transform( (x: Int) => x * 3, _: Int)
 8 into3: Int => Int = <function1>
 9 
10 scala> plus5(6)
11 res6: Int = 11
12 
13 scala> into3(6)
14 res7: Int = 18

Presenter Notes

Pure Function

A Pure Function has no side effects (memory or I/O). This means:

  • Compiler can discard or optimize out the return value if it was not used in an expression
  • The same result is returned for same parameters i.e. one-to-one correspondence or mapping. This can enable caching optimizations such as memoization.
  • Two independent functions can be evaluated out of order, or in parallel without worrying about side-effects.
  • Same strategy can be applied by the compiler if the entire program has many independent functions i.e. many parts of the whole program can run in parrallel, withoug baking-in any paralleism logic!

Presenter Notes

Pure Function examples

1 scala> def stat(num: List[Int]) = { (num.sum, num.sum/num.length.toDouble) }
2 stat: (num: List[Int])(Int, Double)
3 
4 scala> val list1 = List(1,2,3,4,5); val list2 = List(6,7,8,9,10)
5 list1: List[Int] = List(1, 2, 3, 4, 5)
6 list2: List[Int] = List(6, 7, 8, 9, 10)
7 
8 scala> (stat(list1), stat(list2))
9 res57: ((Int, Double), (Int, Double)) = ((15,3.0),(40,8.0))

Presenter Notes

Recursion

A function can call itself, over and over, until a base-case is reached.

Factorial

factorial

1 scala> def factorial(n: Int): Int = { 
2            if(n=0) 1 
3            else n*factorial(n-1)
4        }
5 factorial: (n: Int)Int
6 
7 scala> factorial(5)
8 res2: Int = 120

Presenter Notes

Strict versus non-strict evaluation

Lazy val

1 scala> lazy val a = b + 1; lazy val b = 1;
2 a: Int = <lazy>
3 b: Int = <lazy>
4 
5 scala> a
6 res36: Int = 2
7 
8 scala> b
9 res37: Int = 1

Presenter Notes

Strict versus non-strict evaluation

Call by name

 1 scala> def withinTx(block: () => Unit) = {
 2          println("Begin TX"); block() ; println("End TX")
 3        }
 4 withinTx: (block: () => Unit)Unit
 5 
 6 scala> withinTx { () => println("Performing operation") }
 7 Begin TX
 8 Performing operation
 9 End TX
10 
11 scala> def insideTx(block: => Unit) = {
12           println("Begin TX"); block ; println("End TX")
13        }
14 insideTx: (block: => Unit)Unit
15 
16 scala> insideTx { println("Performing operation") }
17 Begin TX
18 Performing operation
19 End TX

Presenter Notes

Type Systems

  • Typed functions
  • Type bounds ( view bounds, context bounds, manifest context bounds )
  • Variance: co-variant / contra-variant
  • Wildcards

Presenter Notes

Object Oriented Programming

  • Traits
  • Objects
  • Classes
  • Companion Objects ( inside same source file )
  • Structural Types

Presenter Notes

Trait / Object / Class

Just like java has Interface, Scala has Traits, but with definitions.

 1 trait Perishable {
 2     def name: String
 3     def lifespan: Int
 4 }
 5 
 6 class Person {
 7     // class body
 8     def age() = { 19 }
 9 }
10 
11 object TheCat {
12     // object body
13     def sayHelloNTimes(n: Int, name: String): String = { "" }
14 }

Java:

1 interface Animal {
2    public String name();
3    public int lifespan();
4 }

Presenter Notes

Class

1 class Animal {
2   // class body
3   val age = 10
4   def method1(p1: Int, p2: String): String = {
5     /* some operations here */
6   }
7 }
8 
9 val a = new Animal // this is an instance of class Animal

Presenter Notes

Object

Object is not the same as an instance of a class

Object is singleton

1 object Animal {
2   // object body
3   val age = 10 // object member
4   def method1(p1: Int, p2: String): String = { /* some operations here */ }
5 }
6 
7 println(Animal.age)

Presenter Notes

Companion Objects

Objects name same as class name, and inside same source file

 1 class Animal(name: String, lifespan: Int) {
 2   def makeNoise(volume: Int): String = { 
 3     name + " at volume: " + volume
 4   }
 5 }
 6 
 7 object Animal {
 8   def apply(name: String, lifespan: Int) = new Animal(name, lifespan)
 9 }
10 
11 val a0 = new Animal("Mammoth", 100)
12 val a1 = Animal("Elephant", 40)

Presenter Notes

Structural Types

1 def veryLoud(animal: { def makeNoise(vol: Int): String }) = {
2   animal.makeNoise(10)
3 }
4 
5 val a0 = new Animal("Mammoth", 100)
6 veryLoud(a0)

Presenter Notes

OOP: engines

Stroke Engines

StrokeEngine

Presenter Notes

OOP: engines

Steam Engine

SteamEngine

Presenter Notes

Engines

 1 package oop;
 2 import java.util.Arrays;
 3 public class MyEngines {
 4     enum FuelLevel {Empty, Reserve, Half, Full}
 5     interface Startable { public void start(); }
 6     interface Stoppable { public void stop(); }
 7 
 8     abstract class Engine implements Startable, Stoppable { ... }
 9     class TwoStrokeEngine extends Engine { ... }
10     class FourStrokeEngine extends Engine { ... }
11 
12     interface Make { ... }
13     class SteamEngine extends Engine implements Make { ... }
14 
15     public static void main() { ... }
16 }

Continued on next slide...

Presenter Notes

abstract class Engine

 1 abstract class Engine implements Startable, Stoppable {
 2     int horsePower;
 3     FuelLevel fuelLevel;
 4     boolean running = false;
 5     public Engine(int hp, boolean state, FuelLevel fl) {
 6         this.horsePower = hp; this.running = state; this.fuelLevel = fl;
 7     }
 8     @Override
 9     public void start() {
10         switch (fuelLevel) {
11         case Empty:
12             System.out.println("Cannot start without fuel.");
13         default:
14             if (!running) {
15                 running = true;
16                 System.out.println("Engine started");
17             } else System.out.println("Engine already started");
18         }
19     }
20     @Override
21     public void stop() {
22         if (running) {
23             running = false; System.out.println("Engine stopped");
24         }
25     }
26     @Override
27     public String toString() {
28         return String.format(
29          "Engine(running: %s, fuelLevel: %s, horsePower: %d BHP)", running, fuelLevel, horsePower);
30     }
31 }

Presenter Notes

TwoStrokeEngine / FourStrokeEngine

 1 class TwoStrokeEngine extends Engine {
 2     String model;
 3     public TwoStrokeEngine(int hp, boolean state, FuelLevel fl) {
 4         super(hp, state, fl);
 5     }
 6     @Override
 7     public String toString() {
 8         return "TwoStroke" + super.toString();
 9     }
10 }
11 
12 class FourStrokeEngine extends Engine {
13     String model;
14     public FourStrokeEngine(int hp, boolean state, FuelLevel fl) {
15         super(hp, state, fl);
16     }
17     @Override
18     public String toString() {
19         return "FourStroke" + super.toString();
20     }
21 }

Presenter Notes

SteamEngine

 1 interface Make {
 2     public String make();
 3 }
 4 
 5 class SteamEngine extends Engine implements Make {
 6     String model = "IndianRailways";
 7     public SteamEngine(int hp, boolean state, FuelLevel fl) {
 8         super(hp, state, fl);
 9     }
10     public SteamEngine(int hp, boolean state, FuelLevel fl, String modelName) {
11         this(hp, state, fl);
12         this.model = modelName;
13     }
14     @Override
15     public String make() { return "SteamEngine - " + model; }
16     @Override
17     public String toString() {
18         return "Steam" + super.toString();
19     }
20 }

Presenter Notes

make some engines now...

 1 public static void main(String[] args) {
 2 
 3     MyEngines me = new MyEngines();
 4 
 5     FourStrokeEngine e1 = me.new FourStrokeEngine(40, false,
 6             FuelLevel.Empty);
 7     System.out.println(e1);
 8     e1.start(); // won't start
 9     e1.fuelLevel = FuelLevel.Full;
10     e1.start(); // will start: fuel-tank is now full
11     System.out.println(e1 + "\n");
12 
13     TwoStrokeEngine e2 = me.new TwoStrokeEngine(26, false, FuelLevel.Full);
14     System.out.println(e2);
15     e2.start();
16     System.out.println(e2 + "\n");
17 
18     SteamEngine e3 = me.new SteamEngine(1800, true, FuelLevel.Reserve);
19     System.out.println(e3);
20     System.out.println(e3.make() + "\n");
21 
22     Engine[] myengines = { e1, e2, e3 };
23     System.out.println(Arrays.asList(myengines) + "\n");
24 }

Presenter Notes

Scala version

 1 package oop
 2 object engine {
 3   object FuelLevel extends Enumeration {
 4     type FuelLevel = Value
 5     val Empty, Reserve, Half, Full = Value 
 6   }
 7   import FuelLevel._
 8 
 9   trait Stoppable {
10     var running: Boolean
11     var fuelLevel: FuelLevel
12     def stop = if (running) {running = false; println("Engine stopped")}
13   }
14 
15   trait Startable {
16     var running: Boolean
17     var fuelLevel: FuelLevel
18     def start = fuelLevel match {
19         case FuelLevel.Empty => println("Cannot start without fuel.")
20         case _ if ! running => {
21           running = true; println("Engine started")
22         }
23         case _ => println("Engine already running")
24       }
25   }

Presenter Notes

Scala version ...

 1   class Engine(hp: Int, state: Boolean, fl: FuelLevel)
 2     extends Startable with Stoppable {
 3     val horsePower = hp
 4     var fuelLevel = fl
 5     var running = state
 6     override def toString="Engine(running: %s, fuelLevel: %s, horsePower: %dBHP)"
 7       .format(running, fuelLevel, horsePower)
 8   }
 9   class TwoStrokeEngine(hp: Int, state: Boolean, fl: FuelLevel)
10     extends Engine(hp, state, fl) {
11     override def toString = "TwoStroke" + super.toString()
12   }
13   class FourStrokeEngine(hp: Int, state: Boolean, fl: FuelLevel)
14     extends Engine(hp, state, fl) {
15     override def toString = "FourStroke" + super.toString()
16   }
17 
18   trait Make {def make: String}
19 
20   class SteamEngine(hp: Int, state: Boolean, fl: FuelLevel, modelName: String)
21     extends Engine(hp, state, fl) with Make {
22     private val model = modelName
23     def this(hp: Int, state: Boolean, fl: FuelLevel) = this(hp, state, fl, "Toy")
24     def make = "SteamEngine - " + model
25   }

Presenter Notes

Scala version ...

 1   def main(args: Array[String]) {
 2     val e1 = new FourStrokeEngine(40, false, FuelLevel.Empty)
 3     println(e1)
 4     e1.start // won't start
 5     e1.fuelLevel = FuelLevel.Full
 6     e1.start // will start: fuel-tank is now full
 7     println(e1 + "\n")
 8 
 9     val e2 = new TwoStrokeEngine(40, false, FuelLevel.Full)
10     println(e2)
11     e2.start
12     println(e2 + "\n")
13 
14     val e3 = new SteamEngine(300, true, FuelLevel.Reserve)
15     println(e3)
16     println(e3.make + "\n")
17 
18     val myengines = Array(e1, e2, e3)
19     println(myengines + "\n")
20   }
21 }

Presenter Notes

Recap

We covered:

  • Using Scala: Scala tools, Basic Data Types, Collections, if-else, loops, case-match, exception handling
  • Functional Programming in Scala: closure, functions and values, higher order functions, recursion
  • Object Oriented Programming in Scala: Traits, Objects, Classes, Companion Objects, Structural Types

Presenter Notes

Pros / Cons

Pros:

  • Higher Productivity
  • Higher Quality
  • Better Developers
  • Rapidly Improving Ecosystem

Cons:

  • Learning Curve
  • Popularity

Presenter Notes

Scala is like a Swiss Army Knife

Presenter Notes

Use cases of Scala

  • Scala is like a swiss-army-knife. But you only need a normal knife to cut an apple.
  • Remember, Scala is a JVM language
  • Applications which already run on the JVM: Enterprise Integration, Web Services
  • Quick prototyping
  • Concurrent applications for multi-core machines: RxScala, Akka ( based on Erlang's Actor Model )
  • DSLs i.e.Domain Specific Languages
  • And for fun!

Presenter Notes

Who uses Scala ?