Functional and OOP Programming in Scala

Table of Contents

  • Index
  • Repository
  • 1 Scala

    1.1 Overview

    1.1.1 Features

    Scala is a statically typed, functional, object oriented and imperative language created by Martin Odersky , or multi-paradigm programming language that runs in JVM - Java Virtual Machine that allows type-safe programming with high productivity.

    Features:

    • Interactive - Scala REPL allows the user to perform exploratory design and learn and experiment the Java API interactively.
    • Scripting language - Scala has a fast initialization time what makes it suitable for scripting and small proof-concept programs.
    • Java Integration - As a JVM language Scala allows reusing of all Java libraries and integration with old code bases.
    • Multi Paradigm:
      • Imperative
      • Object Oriented
      • Functional
    • Functional Programming Features
      • Lambda function (aka anonymous function)
      • Provides short syntax for curried functions
      • Higher order methods. Functions can be passed as arguments to methods.
      • Type Inference. It frees the developer from declaring typing for all values and functions in a similar way to Haskell, although Scala requires some type anotations.
      • Algebraic Data Types. AGDT is useful for represeting AST - Abstract Syntax Trees; write parsers and compilers and perform symbolic computations.
      • Pattern Matching
      • Tail Call Optimization. TCO makes tail-recursive functions be equivalent to a while loop, hence not consuming stack frames avoiding stack overflows.
      • Rich Collection Library - Collections are standard data structures such as lists, arrays, vectors, hash maps (hash tables, aka dictionaries), tuples and so on with a wide variety of performance guarantees. The collection library provides lots of higher order methods (methods which takes functions as arguments) such as .map, .foreach, .flatMap, .take(n) …
      • Interoperability between OOP and FP - There are lots features and syntax sugars in Scala which makes the integration between OOP and FP smoothly, such as syntax sugars for calling methods, the ability to pass functions and method as arguments of methods or functions and the collection library.
    • Object Oriented Features
      • Pure Object Oriented language - Everything in Scala is an object, there is no primitive types like in Java and all objects can be extended or get extension methods.
      • Better interfaces: Unlike, Java interfaces, Scala traits allows concrete methods.
    • Drawbacks - As everything in the real world, there is always trade-offs.
      • Slower compilation time than Java.
      • Scala generated code is not binary compatible between Scala releases, for instance, a library compiled againt Scala 2.11 may not run when compiled against version 2.12.
      • No convenient syntax sugar for function application which avoids parenthesis, for instance the expression f1(f2(f3(x))) can be written as f1 $ f2 $ f3 $ x in Haskell and as f1 <| f2 <| f3 <| x in F# or using reverse function application as x |> f1 |> f2 |> f3.
      • While it is easy to call Java code from Scala, the inverse is harder due to Scala advanced type system.

    Notes:

    • Scala may also be convenient as first programming language since it provides object oriented programming and functional programming support and also provides access to the whole Java API. The scala REPL (Read-Eval-Print-Loop) also makes experimentation and exploratory design easier.

    1.1.3 File Extensions

    Extension Description
    .scala Scala source code or script
    .java Java source code
       
    .class Java bytecode or compile code
    .jar Java application
       
       

    1.2 Tooling

    1.2.1 Overview

    Program Description
    Scala tools  
    scala Scala REPL or interactive shell like python or ipython.
    scalac Scala compiler.
    scaladoc Documentation builder similar to Javadoc.
    sbt Simple Building Tool. Or scala building tool similar to Maven, but less verbose.
       
    Java tools  
    java Java runtime.
    javac Java compiler.
    javadoc java documentation builder.
       
       

    Other Tools:

    1.2.2 REPL - Scala Shell

    1.2.2.1 REPL Commands

    The Scala REPL or Scala shell allows exploratory design and interactive lerarning about the Java API.

    Command Description
    :help Show help
    :paste Paste a block of code and enter Ctrl+D.
    :paste <path-to-file> Load a file.
    :load <path-to-file> Load a Scala file into the repl.
    :require <path-to-*.jar> Load a Jar file into the REPL.
    :history Show command history
    :reset Reset repl to its initial state.
    :silent Enable/disable automatic printing of results.
    :quit or Ctrl + c Exit REPL
       

    Scala REPL:

    scala-repl-shell1.png

    Example: Load a scala script in the repl. File: src/clockDisplayGui.scala

    scala> :load clockDisplayGui.scala
    Loading clockDisplayGui.scala...
    runTimer: (interval: Int, taskFn: () => Unit)java.util.Timer
    currentTime: ()String
    frame: javax.swing.JFrame = javax.swing.JFrame[frame0,0,0,0x0,invalid,hidden,layout=java.awt.BorderLayout,title=Java Clock App,resizable,normal,defaultCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,0,0,0x0,invalid,layout=javax.swing.JRootPane$RootLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=16777673,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true]
    label: javax.swing.JLabel = javax.swing.JLabel[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=8388608,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,horizontalAlignment=LEADING,horizontalTextPosition=TRAILING,iconTextGap=4,labelFor=,text=,verticalAlignment=CENTER,verticalTextPosition=CENTER]
    res0: java.awt.Component = javax.swing.JLabel[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=8388608,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,horizontalAlignment=LEADING,horizontalTextPosition=TRAILING,iconTextGap=4,labelFor=,text=,verticalAlignment=CENTER,verticalTextPosition=CENTER]
    res3: java.util.Timer = java.util.Timer@455b6df1
    
    ob_scala_eol
    
    1.2.2.2 Running Scala Scripts
    1. Sample script
      import javax.swing.{JFrame, JPanel, JTextArea}
      
      println("Hello world Scala")
      
      val frame = new JFrame("Sample scala script")
      frame.setSize(300, 400)
      frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE)
      
      val tarea = new JTextArea()
      val scroll = new javax.swing.JScrollPane(tarea)
      frame.add(scroll)
      frame.setVisible(true)
      
      tarea.append("Hello world Scala Script")
      tarea.append("\nHello world! (en)")
      tarea.append("\nHola mundo!  (es)")
      tarea.append("\nOla mundo!   (pt)")
      
    2. Running script from command line:
      $ scala scalaScript.scala 
      Hello world Scala
      
      ob_scala_eol
      

      Screenshot:

      scalaScriptRunning.png

    3. Running the script command line with faster initialization.
      • scala -save scalaScript.scala

      It will run the script and compile it to scalaScript.jar that will speed up the initialization when the scala program is invoked again.

      $ scala -save scalaScript.scala 
      Hello world Scala
      
      $ file scalaScript.jar 
      scalaScript.jar: Java archive data (JAR)
      
      $ unzip -l scalaScript.jar 
      Archive:  scalaScript.jar
        Length      Date    Time    Name
      ---------  ---------- -----   ----
             75  2017-06-30 16:02   META-INF/MANIFEST.MF
           1691  2017-06-30 16:02   Main$$anon$1.class
            570  2017-06-30 16:02   Main$.class
            556  2017-06-30 16:02   Main.class
      ---------                     -------
           2892                     4 files
      
      # Next initialization is faster. 
      $ scala scalaScript.scala 
      Hello world Scala
      
      ob_scala_eol
      
      # The generated jar file can be executed directly.
      $ scala scalaScript.jar
      Hello world Scala
      
      ob_scala_eol
      
      # It be executed directly with java and Scala runtime library.
      $ java -cp /home/archbox/opt/scala-2.11.8/lib/scala-library.jar:scalaScript.jar Main 
      Hello world Scala
      
      ob_scala_eol
      
    4. Running script from scala REPL.
      $ scala
      Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_20).
      Type in expressions for evaluation. Or try :help.
      
      scala> :paste scalaScript.scala
      Pasting file scalaScript.scala...
      Hello world Scala
      
      scala> println(tarea.getText())
      Hello world Scala Script
      Hello world! (en)
      Hola mundo!  (es)
      Ola mundo!   (pt)
      
      Write something more. 
      
      Scala allows to write apps with GUIs fast!!
      
      Like in Smalltalk, in Scala all objects 
      and functions are right at your fingers.
      
      scala> tarea.setText("Hello world Java Swing")
      
      scala>
      
    5. Scala script as Unix executable

      Scala scripts can be executed as ordinary *nix shell scripts like bash scripts with ./scala-script.scala

      Example:

      file: src/scalaNix.scala - This script shows all arguments passed by the user and displays a file in GUI (Graphical User Interface) passed as first argument arg(0).

      #!/bin/sh
      exec scala -save "$0" "$@"
      !#
      
      // Display text in a GUI
      def displayText(text: String) = {
        import javax.swing.{JFrame, JTextArea, JScrollPane}
        val tarea = new JTextArea()
        val frame = new JFrame()
        frame.add(new JScrollPane(tarea))
        frame.setSize(400, 500)
        frame.setVisible(true)
        frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE)
        tarea.setText(text)
      }
      
      
      def readFile(file: String) = {
        val src = scala.io.Source.fromFile(file)
        val txt = src.mkString
        src.close()
        txt
      }
      
      println("Testing Scala script")
      
      println("Arguments passed by user")
      
      args.foldLeft(0){(acc, a) =>
        println(s"arg[${acc}] = ${a}")
        acc + 1
      }
      
      
      displayText(readFile(args(0)))
      

      Running it: It will display the file file:///etc/protocols in a Linux-based distribution passed as first argument arg(0).

      $ src/scalaNix.scala /etc/protocols arg1 arg2 arg3 arg4
      
      Testing Scala script
      Arguments passed by user
      arg[0] = /etc/protocols
      arg[1] = arg1
      arg[2] = arg2
      arg[3] = arg3
      arg[4] = arg4
      

    1.2.3 Scalac - Scala compiler

    1.2.3.1 Sample scala program
    package scalaApp
    
    import javax.swing.{JFrame, JPanel, JTextArea}
    
    object Main{
    
      def main(arrgs: Array[String]){
        println("Hello world Scala")
    
        val frame = new JFrame("Sample scala script")
        frame.setSize(300, 400)
        frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE)
    
        val tarea = new JTextArea()
        val scroll = new javax.swing.JScrollPane(tarea)
        frame.add(scroll)
        frame.setVisible(true)
    
        tarea.append("Hello world Scala Script")
        tarea.append("\nHello world! (en)")
        tarea.append("\nHola mundo!  (es)")
        tarea.append("\nOla mundo!   (pt)")
    
      }
    }
    
    1.2.3.2 Compiling

    Compiling:

    # Compile 
    $ scalac scalaProgram.scala 
    
    # Inspect generated files.
    $ ls scalaApp/
     Main.class  'Main$.class'
    
    $ file scalaApp/Main.class 
    scalaApp/Main.class: compiled Java class data, version 50.0 (Java 1.6)
    

    Running with scala:

    $ scala scalaApp.Main 
    Hello world Scala
    

    Running directly with java:

    $ java -cp .:/home/archbox/opt/scala-2.11.8/lib/scala-library.jar scalaApp.Main
    Hello world Scala
    

    Screenshot:

    scalaScriptRunning.png

    1.2.3.3 Compiling to a jar file

    Compiling:

    $ scalac scalaProgram.scala -d scalaApp.jar 
    
    # Inspect generated file.
    $ file scalaApp.jar 
    scalaApp.jar: Java archive data (JAR)
    
    # View package contents with jar tool.
    $ jar tf scalaApp.jar 
    META-INF/MANIFEST.MF
    scalaApp/Main.class
    scalaApp/Main$.class
    
    # View package contents with unzip tool.
    $ unzip -l scalaApp.jar 
    Archive:  scalaApp.jar
      Length      Date    Time    Name
    ---------  ---------- -----   ----
           84  2017-06-30 16:50   META-INF/MANIFEST.MF
          586  2017-06-30 16:50   scalaApp/Main.class
         1369  2017-06-30 16:50   scalaApp/Main$.class
    ---------                     -------
         2039                     3 files
    

    Running with scala:

    $ scala scalaApp.jar 
    Hello world Scala
    

    Running with java:

    $ java -cp scalaApp.jar:/home/archbox/opt/scala-2.11.8/lib/scala-library.jar scalaApp.Main
    Hello world Scala
    

    or

    $ cp /home/archbox/opt/scala-2.11.8/lib/scala-library.jar .
    $ java -cp scalaApp.jar:scala-library.jar scalaApp.Main
    Hello world Scala
    

    1.3 Basic Syntax

    1.3.1 Comments

    // Single line comment
    
    /*
    Multiline Comment
    
    */
    
    /**
      * Documentation comment.
      *
      */
    

    Cooment with Scala-Doc markup. It allows Scaladoc to extract the documentation from comment and produce an html documentation such as Doxygen for C or C++ and Javadoc for Java do.

    /** This function computes the distance from origin (0, 0) to point (x, y)
      *
      *  Usage Example:
      *
      *  {{{
      *     scala> distancePoint(30.0, 40.0)
      *     res11: Double = 50.0
      *  }}}
      *
      *  @param x  - X coordinate of point
      *  @param y  - Y coordinate of point
      *  @return  Distance from origin to point (x, y)
      */
    def distancePoint(x: Double, y: Double) =
      Math.sqrt(x * x + y * y)
    

    1.3.2 Values and Variables Declaration

    Value

    It is not possible to reassign values.

    scala> val x = 10.2323
    x: Double = 10.2323
    
    scala> x = 1.5354
    <console>:12: error: reassignment to val
           x = 1.5354
    
    scala> val a = "hello world"
    a: String = hello world
    
      // Scala has multi-line string, unlike Java.
      val s = """Hello world
      Scala
      String
      """
    

    It is not possible to change a reference to object stored in a value. For instance, the reference to the object of class/type JFrame with title "Hello World" cannot be changed, although the the object can be changed.

    scala> val frame = new javax.swing.JFrame("Hello world")
    frame: javax.swing.JFrame = javax.swing.JFrame[frame0,0,27,0x0,invalid,hidden ...]
    
    // --- Try to change the reference stored in the value.
    //
    scala> val frame2 = new javax.swing.JFrame("Hello world")
    frame2: javax.swing.JFrame = javax.swing.JFrame[frame1,0,27 ...]
    
    scala> frame = frame2
    <console>:13: error: reassignment to val
           frame = frame2
    
    // A copy of the object previously defined is not created,
    // only the reference (pointer) of this object is copied.
    //
    scala> val frameCopy = frame
    frameCopy: javax.swing.JFrame = javax.swing.JFrame[frame3,0,2 ... ..
    
    scala> frame.getTitle
    res18: String = Hello world
    
    scala> frameCopy.getTitle
    res12: String = Hello world
    
    scala> frame.setTitle("Scalability and growth")
    
    scala> frameCopy.setTitle("Scalability and growth")
    
    scala> frame.getTitle
    res22: String = Scalability and growth
    
    scala> frame.setTitle("Scalable scalable scalable ...")
    
    scala> frameCopy.getTitle
    res24: String = Scalable scalable scalable ...
    
    // Eq - Method checks for reference equality. So, if the references (pointer to object) to
    // objects are equal, then the return value should be true.
    //
    scala> frameCopy eq frame
    res15: Boolean = true
    
    scala> frameCopy.eq(frame)
    res16: Boolean = true
    
    scala> frame.eq(frameCopy)
    res17: Boolean = true
    

    Values declared with explicit type annotation:

    scala> val x: Double = 20.03
    x: Double = 20.03
    
    scala> val y: Double = "hello world"
    <console>:11: error: type mismatch;
     found   : String("hello world")
     required: Double
           val y: Double = "hello world"
                           ^
    
    scala> val point: (Int, Int) = (100, 200)
    point: (Int, Int) = (100,200)
    
    scala> val point2: (Int, Int) = -100.34
    <console>:11: error: type mismatch;
     found   : Double(-100.34)
     required: (Int, Int)
           val point2: (Int, Int) = -100.34
    
    
    scala> type Action = () => Unit
    defined type alias Action
    
    scala> val act1: Action = () => println("Print to screen1")
    act1: Action = $$Lambda$1109/363103401@b56c222
    
    scala> printer1("hello world Scala is super scalable!!")
    hello world Scala is super scalable!!
    

    Variable

    Unlike a value, a variable allows reassignment and change the reference to the pointed object.

    scala> var x = 10.2334
    x: Double = 10.2334
    
    scala> x = 4.5
    x: Double = 4.5
    
    scala> var s = "Hello"
    s: String = Hello
    
    scala> s = "world"
    s: String = world
    
    scala>
    

    Variables can be declared with type annotation too:

    scala> var x: Double = 10.0
    x: Double = 10.0
    
    scala> x = 2
    x: Double = 2.0
    
    scala> x = 45.43
    x: Double = 45.43
    
    
    // Declare a variable holding a reference to a function
    // with default NULL value.
    // WARNING. Null should be used with caution.
    scala> var action: String => Unit = null
    action: String => Unit = null
    
    scala> action("testing Scala")
    java.lang.NullPointerException
      ... 28 elided
    
    scala> action = s => println("Message = " + s)
    action: String => Unit = $$Lambda$1171/1365490452@2865c8db
    
    scala> action("testing Scala")
    Message = testing Scala
    
    // Print to stderr - Store reference to method (.println) of System.err object.
    scala> action = System.err.println
    action: String => Unit = $$Lambda$1172/1358395794@2f533bd1
    
    scala> action("testing Scala")
    testing Scala
    

    1.3.3 Scope

    val x = 10 
    val y = 15 
    val z = x + y 
    
    scala> val x = 10 
    x: Int = 10
    
    scala> val y = 15 
    y: Int = 15
    
    scala> val z = x + y 
    z: Int = 25
    
    // Local Scope 
    scala> { val x  = 5 ; val y = 4 ; val z = x + y ; println("z = " + z) }
    z = 9
    
    // Values from local scope are not affected by the values of local one.
    scala> x
    res4: Int = 10
    
    scala> y
    res5: Int = 15
    
    
    scala> val k1 = { println("k1 set to 5.0") ; 5.0 }
    k1 set to 5.0
    k1: Double = 5.0
    
    scala> 2 * k1
    res1: Double = 10.0
    

    Return value from scope:

    val z2 = {
      val a = 2
      val b = 5
      // Return value from scope is the last value
      a + b
    }
    
    scala> val z2 = {
         |   val a = 2
         |   val b = 5
         |   // Return value from scope is the last value
         |   a + b
         | }
    z2: Int = 7
    
    scala> a
    <console>:12: error: not found: value a
           a
           ^
    
    scala> b
    <console>:12: error: not found: value b
           b
           ^
    

    1.3.4 Import Java and Scala Libraries

    Import everythign from namespace java.io. Equivalent to java statement (import java.io.*).

    scala> import java.io._
    import java.io._
    
    scala> val fd = new FileWriter("/tmp/testfile.txt")
    fd: java.io.FileWriter = java.io.FileWriter@1eceaded
    
    scala> fd.write("hello world")
    
    scala> fd.close()
    

    Import multiple classes

    scala> import javax.swing.JFrame
    import javax.swing.JFrame
    
    scala> import javax.swing.{JFrame, JPanel, JLabel}
    import javax.swing.{JFrame, JPanel, JLabel}
    
    scala> val frame = new JFrame("Hello world Scala")
    
    scala> frame.setSize(300, 400)
    
    scala> frame.setVisible(true)
    

    or

    scala> val frame = new javax.swing.JFrame("Hello world Scala")
    
    scala> frame.setSize(300, 400)
    
    scala> frame.setVisible(true)
    

    Import members / functions from a static class.

    @ import Math.{PI, sin, cos, tan, exp} 
    import Math.{PI, sin, cos, tan, exp}
    
    @ Math.sin(Math.PI) 
    res7: Double = 1.2246467991473532E-16
    
    @ sin(PI) 
    res4: Double = 1.2246467991473532E-16
    
    @ cos(PI) 
    res5: Double = -1.0
    
    @ exp(-2.0) 
    res6: Double = 0.1353352832366127
    

    or

    scala> import Math._ // Import everything 
    import Math._
    
    // Or: Import all static methods of class java.lang.Math to use them as functions.
    scala> import java.lang.Math._
    import java.lang.Math._
    
    scala> sin _
    res7: Double => Double = $$Lambda$1197/1482753855@56352274
    
    scala> cos _
    res8: Double => Double = $$Lambda$1198/1338109470@64deb236
    
    scala> sin(PI)
    res9: Double = 1.2246467991473532E-16
    
    scala> List(30, 45, 60, 90, 180).map{x => sin(x * PI / 180.0)} foreach println
    0.49999999999999994
    0.7071067811865475
    0.8660254037844386
    1.0
    1.2246467991473532E-16
    

    Import from singletons / objects

    @ object Module{ 
        def fn(x: Int) = x * 3
        def fxy(a: Int, b: Int) = a + b 
        val gravity = 9.81 
      } 
    defined object Module
    
    @ Module.fn(4) 
    res9: Int = 12
    
    @ Module.fxy(10, 12) 
    res10: Int = 22
    
    @ import Module.{fn, fxy} 
    import Module.{fn, fxy}
    
    @ fn(4) 
    res12: Int = 12
    
    @ fxy(10, 12) 
    res13: Int = 22
    

    Method Syntax

    scala> Math.log10(1000)
    res16: Double = 3.0
    
    scala> Math log10 1000
    res17: Double = 3.0
    
    scala> List(1.0, 10.0, 100.0, 1000.0, 10000.0).map(Math.log10)
    res20: List[Double] = List(0.0, 1.0, 2.0, 3.0, 4.0)
    
    scala> List(1.0, 10.0, 100.0, 1000.0, 10000.0) map Math.log10
    res21: List[Double] = List(0.0, 1.0, 2.0, 3.0, 4.0)
    

    1.4 Functions

    1.4.1 Function Definition

    def prod(x: Int, y: Int) = x * y
    
    scala> prod(4, 5)
    res11: Int = 20
    
    
    def fun(a: Int, b: Int) = {
      val c = 3 * a + b
      val d = b - a
      c * d // The return value is the last value
    }
    
    /**
       a = 4 and b = 5
       c = 3 * a + b = 3 * 4 + 5 = 17
       d = b - a     = 5 - 4 = 1
    
    Return value:
       c * d = 17 * 1
    
    --------------- */
    scala> fun(4, 5)
    res8: Int = 17
    
    
    def showFiles(path: String) = {
      val file = new java.io.File(path)
      file.listFiles.foreach(println)
    }
    
    // Pasting in the REPL
    scala> def showFiles(path: String) = {
         |   val file = new java.io.File(path)
         |   file.listFiles.foreach(println)
         | }
    showFiles: (path: String)Unit
    
    
    scala> showFiles("/")
    /home
    /var
    /bin
    /usr
    /root
    /Applications
    /proc
    /boot
    /dev
    ... ...
    
    
    

    1.4.2 Anonymous Functions / Lambda Functions or Function Literals

    Simple Anonymous Functions

    scala> val mulBy10 = (x: Int) => x * 10
    mulBy10: Int => Int = <function1>
    
    scala> mulBy10(5)
    res25: Int = 50
    
    scala>
    
    scala> val add = (x: Double, y: Double) => x + y
    addV1: (Double, Double) => Double = <function2>
    
    scala> add(10, 20)
    res26: Double = 30.0
    

    Multi line anonymous functions

    val func = (a: Double, b: Double) => {
      val m = a * b
      val n = a * a * 3 - 4.5 * b
      (m, n, m + n)
    }
    
    scala> val func = (a: Double, b: Double) => {
         |   val m = a * b
         |   val n = a * a * 3 - 4.5 * b
         |   (m, n, m + n)
         | }
    func: (Double, Double) => (Double, Double, Double) = <function2>
    
    scala> func(3, 5)
    res28: (Double, Double, Double) = (15.0,4.5,19.5)
    
    scala> func(4, 3)
    res29: (Double, Double, Double) = (12.0,34.5,46.5)
    
    scala>
    

    1.4.3 Curried Functions

    Function in non-curried form (Tuple):

    scala> def mulxy (x: Int, y: Int) = x * y
    mulxy: (x: Int, y: Int)Int
    
    scala> mulxy(3, 4)
    res37: Int = 12
    
    
    scala> List(1, 2, 3, 4, 5).map(mulxy(3, _))
    res38: List[Int] = List(3, 6, 9, 12, 15)
    
    
    scala> List(1, 2, 3, 4, 5).map(mulxy(_, 4))
    res39: List[Int] = List(4, 8, 12, 16, 20)
    

    Function in Curried Form:

    scala> def mulxy (x: Int) (y: Int) = x * y
    mulxy: (x: Int)(y: Int)Int
    
    scala> mulxy _
    res89: Int => (Int => Int) = <function1>
    
    scala> mulxy(3)_
    res88: Int => Int = <function1>
    
    scala> mulxy(3)(4)
    res90: Int = 12
    
    scala> List(2, 3, 4, 5).map(mulxy(5))
    res91: List[Int] = List(10, 15, 20, 25)
    
    scala> List(2, 3, 4, 5) map mulxy(5)
    res38: List[Int] = List(10, 15, 20, 25)
    

    Curried anonymous functions

    scala> val mulNonCurried = (x: Int, y: Int) => x * y
    mulNonCurried: (Int, Int) => Int = <function2>
    
    scala> mulNonCurried(3, 5)
    res30: Int = 15
    
    
    scala> val mulCurried = (x: Int) => (y: Int) => x * y
    mulCurried: Int => (Int => Int) = <function1>
    
    scala> mulCurried(5)
    res32: Int => Int = <function1>
    
    scala> mulCurried(5)(4)
    res33: Int = 20
    
    scala> List(1, 2, 3, 4, 5).map(mulCurried(4))
    res34: List[Int] = List(4, 8, 12, 16, 20)
    
    scala> List(1, 2, 3, 4, 5)  map mulCurried(4)
    res35: List[Int] = List(4, 8, 12, 16, 20)
    

    1.4.4 Closures

    1.4.4.1 Simple closure example
    def makeMultiplier(factor: Double) = {
      val m = (factor + 1.0) * factor
      val n = factor / 100.0
      (x: Double) => x * m + n
    }
    
    scala> def makeMultiplier(factor: Double) = {
         |   val m = (factor + 1.0) * factor
         |   val n = factor / 100.0
         |   (x: Double) => x * m + n
         | }
    makeMultiplier: (factor: Double)Double => Double
    
    
    scala> val fn1 = makeMultiplier(3.0)
    fn1: Double => Double = <function1>
    
    scala> val fn2 = makeMultiplier(4.0)
    fn2: Double => Double = <function1>
    
    scala> fn1(1)
    res40: Double = 12.03
    
    scala> fn1(2)
    res41: Double = 24.03
    
    scala> fn2(1)
    res42: Double = 20.04
    
    scala> fn1(2)
    res43: Double = 24.03
    
    1.4.4.2 Stateful functions

    Example 1

    // Version 1
    //
    def makeIncrementer1() = {
      var counter = 0
      val inc = () => {
        val c   = counter
        counter = counter + 1
        c
      }
    
      inc
    }
    
    scala> def makeIncrementer1() = {
         |   var counter = 0
         |   val inc = () => {
         |     val c   = counter
         |     counter = counter + 1
         |     c
         |   }
         |
         |   inc
         | }
    makeIncrementer1: ()() => Int
    
    scala> val inc = makeIncrementer1()
    inc: () => Int = <function0>
    
    scala> inc()
    res22: Int = 0
    
    scala> inc()
    res23: Int = 1
    
    scala> inc()
    res24: Int = 2
    
    scala> inc()
    res25: Int = 3
    
    scala> inc()
    res26: Int = 4
    
    
    scala> val inc2 = makeIncrementer1()
    inc2: () => Int = <function0>
    
    scala> inc2()
    res27: Int = 0
    
    scala> inc2()
    res28: Int = 1
    
    scala> inc2()
    res29: Int = 2
    
    scala> inc2()
    res30: Int = 3
    
    ... ...
    
    
    // Version 2
    //
    def makeIncrementer2() = {
      var counter = 0
      () => {
        val c   = counter
        counter = counter + 1
        c
      }
    }
    
    scala> def makeIncrementer2() = {
         |   var counter = 0
         |   () => {
         |     val c   = counter
         |     counter = counter + 1
         |     c
         |   }
         | }
    makeIncrementer2: ()() => Int
    
    scala> val inc3 = makeIncrementer
    makeIncrementer1   makeIncrementer2
    
    scala> val inc3 = makeIncrementer2()
    inc3: () => Int = <function0>
    
    scala> inc3()
    res31: Int = 0
    
    scala> inc3()
    res32: Int = 1
    
    scala> inc3()
    res33: Int = 2
    
    scala> val inc4 = makeIncrementer2()
    inc4: () => Int = <function0>
    
    scala> inc4()
    res34: Int = 0
    
    scala> inc4()
    res35: Int = 1
    
    scala> inc4()
    res36: Int = 2
    
    ...
    

    Example 2

    def makeCounter() = {
      var counter = 0
    
      val inc = () => {
        val c = counter
        counter = counter + 1
        c
      }
    
      val dec = () => {
        val c = counter
        counter = counter - 1
        c
      }
    
      (inc, dec)
    }
    
    scala> def makeCounter() = {
         |   var counter = 0
         |
         |   val inc = () => {
         |     val c = counter
         |     counter = counter + 1
         |     c
         |   }
         |
         |   val dec = () => {
         |     val c = counter
         |     counter = counter - 1
         |     c
         |   }
         |
         |   (inc, dec)
         | }
    makeCounter: ()(() => Int, () => Int)
    
    scala> val (inc, dec) = makeCounter()
    inc: () => Int = <function0>
    dec: () => Int = <function0>
    
    scala> inc()
    res48: Int = 0
    
    scala> inc()
    res49: Int = 1
    
    scala> inc()
    res50: Int = 2
    
    scala> dec()
    res51: Int = 3
    
    scala> dec()
    res52: Int = 2
    
    scala> dec()
    res53: Int = 1
    
    scala> dec()
    res54: Int = 0
    
    scala> inc()
    res55: Int = -1
    
    scala> inc()
    res56: Int = 0
    
    scala> inc()
    res57: Int = 1
    
    1.4.4.3 Emulating Objects with closures
    // Record of functions
    //
    case class Counter(
          increment: () => Unit
         ,decrement: () => Unit
         ,get:       () => Int
    )
    
    // The internal state counter can only be accessed using the "methods" or
    // functions increment, decrement and get.
    //
    def newCounter(init: Int) = {
      var counter = init
      Counter(
           () => { counter = counter + 1}
          ,() => { counter = counter - 1}
          ,() => counter
       )
    }
    
    scala> val c = newCounter(0)
    c: Counter = Counter(<function0>,<function0>,<function0>)
    
    scala> c.increment _
    res1: () => () => Unit = <function0>
    
    scala> c.decrement _
    res2: () => () => Unit = <function0>
    
    scala> c.get
    get   getClass
    
    scala> c.get _
    res3: () => () => Int = <function0>
    
    scala> c.get()
    res11: Int = 0
    
    scala> c.increment()
    
    scala> c.get()
    res13: Int = 1
    
    scala> c.increment()
    
    scala> c.get()
    res15: Int = 2
    
    scala> c.increment() ; c.get()
    res16: Int = 3
    
    scala> c.increment() ; c.get()
    res17: Int = 4
    
    scala> c.increment() ; c.get()
    res18: Int = 5
    
    scala> c.decrement() ; c.get()
    res19: Int = 4
    
    scala> c.decrement() ; c.get()
    res20: Int = 3
    
    scala> c.decrement() ; c.get()
    res21: Int = 2
    

    1.4.5 Nested Functions

    As Scala has closures or lexical scope, it is possible to define functions inside functions which avoids code repetition and polluting the local scope.

    /**  Pretty print a collection of tuples as a table. 
      Parameters: 
      @rows     - Collection of tuples to be printed.  
      @title    - Tuple containing the titles of left and right side. 
      @line     - Flag that if set to true, prints a new line between each row.
      @margin   - Margin from left side of screen as number of spaces.
      @sep      - Number of spaces between left side and right side 
      @maxRside - Maximum number of characters to printed on right side.
      */ 
    def printTupleAsTable(
      rows:   Seq[(String, String)],
      title:  (String, String) = ("", ""),
      line:   Boolean = false,
      margin: Int = 0,
      sep:    Int = 4,
      maxRside: Int = 100
    ) = {
    
      def printRow(wmax1: Int, clamp: Boolean = true) = (row: (String, String)) => {
        val (lside, rside) = row
    
        // print left margin 
        for (a <- 0 to margin) print(' ')
    
        print(lside)
    
        // Print spaces 
        for (a <- 0 to wmax1 - lside.length + sep) print(' ')
    
        if (rside.length <= maxRside) {
          println(rside)
        } else if (clamp){
          val dots = "..."
          println(rside.take(maxRside - dots.length) + dots)
        } else {
          println(rside.take(maxRside))
        }
    
        // Print line between rows 
        if (line) println()
      }
    
      def printDashes(wmax1: Int) = {
        printRow(wmax1, false)("-" * wmax1, "-" * maxRside)
      }
    
      val (title1, title2) = title
    
      // Maximum length of left side column 
      val wmax1 = title1.length max rows.map(row => row._1.length).max
    
      printRow(wmax1)(title)
      printDashes(wmax1)
      rows foreach printRow(wmax1)
      printDashes(wmax1)
    }
    

    Running:

    import scala.collection.JavaConverters._
    
    scala> System.getProperties.asScala.toSeq foreach println
    (env.emacs,)
    (java.runtime.name,OpenJDK Runtime Environment)
    (sun.boot.library.path,/usr/lib/jvm/java-8-openjdk/jre/lib/amd64)
    (java.vm.version,25.141-b15)
    (java.vm.vendor,Oracle Corporation)
    (java.vendor.url,http://java.oracle.com/)
    (path.separator,:)
    (java.vm.name,OpenJDK 64-Bit Server VM)
    (file.encoding.pkg,sun.io)
    (user.country,US)
    (sun.java.launcher,SUN_STANDARD)
    ... ... ... ... ... ... ... ... ... ... ... ... ... ... 
    
    
    scala> printTupleAsTable(System.getProperties.asScala.toSeq, title = ("Java Property", "Value"), maxRside = 60)
     Java Property                     Value
     -----------------------------     ------------------------------------------------------------
     env.emacs                         
     java.runtime.name                 OpenJDK Runtime Environment
     sun.boot.library.path             /usr/lib/jvm/java-8-openjdk/jre/lib/amd64
     java.vm.version                   25.141-b15
     java.vm.vendor                    Oracle Corporation
     java.vendor.url                   http://java.oracle.com/
     path.separator                    :
     java.vm.name                      OpenJDK 64-Bit Server VM
     file.encoding.pkg                 sun.io
     user.country                      US
     sun.java.launcher                 SUN_STANDARD
     sun.os.patch.level                unknown
     java.vm.specification.name        Java Virtual Machine Specification
     user.dir                          /home/archbox/test
    
    ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... .
    
     java.vm.info                      mixed mode
     java.version                      1.8.0_141
     java.ext.dirs                     /usr/lib/jvm/java-8-openjdk/jre/lib/ext:/usr/java/package...
     sun.boot.class.path               /usr/lib/jvm/java-8-openjdk/jre/lib/resources.jar:/usr/li...
     java.vendor                       Oracle Corporation
     file.separator                    /
     java.vendor.url.bug               http://bugreport.sun.com/bugreport/
     sun.io.unicode.encoding           UnicodeLittle
     sun.cpu.endian                    little
     sun.cpu.isalist                   
     -----------------------------     ------------------------------------------------------------
    
    
    
    printTupleAsTable(
      rows = System.getenv.asScala.toSeq,
      title = ("Environment Variables", "Value"),
      margin = 5,
      maxRside = 60
    )
    
    scala> printTupleAsTable(
         |   rows = System.getenv.asScala.toSeq,
         |   title = ("Environment Variables", "Value"),
         |   margin = 5,
         |   maxRside = 60
         | )
          Environment Variables        Value
          ------------------------     ------------------------------------------------------------
          PATH                         /usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/defa...
          XAUTHORITY                   /home/archbox/.Xauthority
          LC_MEASUREMENT               pt_BR.UTF-8
          LC_TELEPHONE                 pt_BR.UTF-8
          GDMSESSION                   xfce
          XDG_DATA_DIRS                /usr/local/share:/usr/share
          LC_TIME                      pt_BR.UTF-8
          DBUS_SESSION_BUS_ADDRESS     unix:path=/run/user/1001/bus
          XDG_CURRENT_DESKTOP          XFCE
          MAIL                         /var/spool/mail/archbox
          SSH_AGENT_PID                29199
          MOZ_PLUGIN_PATH              /usr/lib/mozilla/plugins
          COLORTERM                    truecolor
          SESSION_MANAGER              local/ghostpc:@/tmp/.ICE-unix/29194,unix/ghostpc:/tmp/.IC...
          LC_PAPER                     pt_BR.UTF-8
          LOGNAME                      archbox
          PWD                          /home/archbox/test
    
         ... .... ...   ... .... ...   ... .... ...   ... .... ...   ... .... ...   ... .... ...
    
          EDITOR                       emacs -Q -nw --no-site -eval "(progn (setq  inhibit-start...
          NLSPATH                      /usr/dt/lib/nls/msg/%L/%N.cat
          QT_QPA_PLATFORMTHEME         qt5ct
          XDG_RUNTIME_DIR              /run/user/1001
          XDG_VTNR                     7
          HOME                         /home/archbox
          ------------------------     ------------------------------------------------------------
    

    1.4.6 Function Composition

    Math Composition

    Computes f.compose(g) = f°g (x) = f(g(x))

    • f°g (3) = f(g(3)) = f(2*3) = f(6) = 6 + 10 = 16 ok.
                          f ° g = f(g(x))
       ....................................................
       .  ___________________      ___________________    .
       .  |                 |      |                 |    .
       .  |                 |      |                 |    .
     --+->+ g(x) = x * 2    +-->---+  f(x) = x + 10  +----+-->
    4  .  | g(4) = 8        |  8   |  f(8) = 18      |    . 18
       .  |_________________|      +-----------------+    .
       .                                                  .
       ....................................................
    
          ................
          .              .
     4 -->+  (f ° g) (x) +--> 18
          .  f(g(x))     .
          ................
    
    scala> val f = (x: Int) => x + 10
    f: Int => Int = <function1>
    
    scala> val g = (x: Int) => x * 2
    g: Int => Int = <function1>
    
    
    scala> val comp1 = f.compose(g)
    comp1: Int => Int = <function1>
    
    
    scala> comp1(3)
    res70: Int = 16
    
    scala> List(1, 2, 3, 4, 5).map(comp1)
    res71: List[Int] = List(12, 14, 16, 18, 20)
    
    scala>
    
    
    /// It could also be:
    
    scala> val comp11 = f compose g
    comp11: Int => Int = <function1>
    
    scala> List(1, 2, 3, 4, 5).map(comp11)
    res72: List[Int] = List(12, 14, 16, 18, 20)
    

    Reverse Composition (andThen)

    • f.andThen(g) = f >> g = g(f(x))
    • (f andThen g)(4) = (f >> g)(4) = g(f(4)) = g(14) = 28 . Ok.
                          f >> g = g ° f = g(f(x))
       ....................................................
       .   ___________________      ___________________   .
       .  |                 |      |                 |    .
       .  |                 |      |                 |    .
     ---->+ f(x) = x + 10   +-->---+  g(x) = x * 2   +----+-->
    4  .  | f(4) = 14       |  14  |  g(14) = 28     |    . 28
       .  |_________________|      +-----------------+    .
       .                                                  .
       ....................................................
    
    
          .................
          .               .
     4 -->+  (f >> g) (x) +--> 28
          .  g(f(x))      .
          .................
    
    scala> val f = (x: Int) => x + 10
    f: Int => Int = <function1>
    
    scala> val g = (x: Int) => x * 2
    g: Int => Int = <function1>
    
    scala> val f_rcomp_g = f andThen g
    f_rcomp_g: Int => Int = <function1>
    
    scala> f_rcomp_g (4)
    res76: Int = 28
    
    // Or
    scala> f.andThen(g)(4)
    res77: Int = 28
    

    1.4.7 Higher Order Functions

    def sumFn1(f: Int => Int, g: Int => Int, x: Int) = f(x) + g(x)
    
    scala> def sumFn1(f: Int => Int, g: Int => Int) (x: Int) = f(x) + g(x)
    sumFn: (f: Int => Int, g: Int => Int)(x: Int)Int
    
    
    scala>  sumFn1(x => x * 4, a => a + 5, 4)
    res46: Int = 25
    
    scala>  sumFn1(x => x * 4, a => a + 5, 5)
    res47: Int = 30
    
    scala>  sumFn1(x => x * x, a => a + 5, 5)
    res48: Int = 35
    
    
    def sumFn2(f: Int => Int, g: Int => Int) = (x: Int) => f(x) + g(x)
    
    scala> f1(3)
    res49: Int = 20
    
    scala> f1(5)
    res50: Int = 30
    
    scala> val f2 = sumFn2(x => x * x, a => a + a)
    f2: Int => Int = <function1>
    
    scala> f2(3)
    res51: Int = 15
    
    scala> f2(5)
    res52: Int = 35
    
    
    
    def iterFiles(fn: String => Unit) = (path: String) => {
      val f = new java.io.File(path)
      f.listFiles().foreach(file => fn(file.toString))
    }
    
    scala> iterFiles(println)("/")
    /home
    /var
    /bin
    /usr
    /root
    /Applications
    /proc
    /boot
    /dev
      ...
    
    scala> val showFiles = iterFiles(println)
    showFiles: String => Unit = <function1>
    
    
    scala> showFiles("/etc")
    /etc/systemd
    /etc/motd
    /etc/gemrc
    /etc/adobe
    /etc/ld.so.cache
    /etc/environment
    /etc/libreoffice
    /etc/rc_keymaps
    /etc/sensors3.conf
    ... ...
    

    1.4.8 Polymorphic Functions

    1.4.8.1 Generic Functions - functions with type parameters
    def identity[A](x: A) = x
    
    scala> def identity[A](x: A) = x
    identity: [A](x: A)A
    
    scala> identity(100)
    res4: Int = 100
    
    scala> identity(Some(300))
    res5: Some[Int] = Some(300)
    
    scala> identity("Hello world")
    res6: String = Hello world
    
    
    def constantly[A, B](a: A) = (b: B) => a
    
    scala> constantly(100)
    res7: Any => Int = <function1>
    
    scala> constantly(100)("Hello")
    res8: Int = 100
    
    scala> constantly(100)("world")
    res9: Int = 100
    
    scala> constantly(100)(Some(400))
    res10: Int = 100
    
    scala> def show[A](a: A) = a.toString
    show: [A](a: A)String
    
    
    scala> show(340.343)
    res12: String = 340.343
    
    scala> show(Some(1000))
    res13: String = Some(1000)
    
    scala> show(None)
    res14: String = None
    
    1.4.8.2 Functions with multiple signatures

    Multiple functions can share the same name with different signatures if they don't have any default parameter.

    object Dialog {
    
      def showAlert(message: String){
        javax.swing.JOptionPane.showMessageDialog(
             null
            ,message
            ,"Alert"
            ,javax.swing.JOptionPane.WARNING_MESSAGE
         )
      }  
    
      def showAlert(title: String, message: String){
        javax.swing.JOptionPane.showMessageDialog(
             null
            ,message
            ,title
            ,javax.swing.JOptionPane.WARNING_MESSAGE
         )
      }  
    }
    

    Example:

    scala> Dialog.showAlert("Error: Network failure. Could not fetch data")
    
    scala> Dialog.showAlert("Error report", "Error: Network failure. Could not fetch data")
    

    1.4.9 Storing Functions in Data Structures

    As in any language with first class functions, functions can be stored in data structures such as lists, arrays, maps and also stored in objects.

    • Storing functions in variables:
    scala> var printer: (String) => Unit = s => ()
    printer: String => Unit = $$Lambda$1031/1414431049@7fb66650
    
    scala> printer("Test printer")
    
    scala> printer = println
    printer: String => Unit = $$Lambda$1060/1256918571@648c5fb3
    
    scala> printer("Test printer")
    Test printer
    
    // Print to stdout
    scala> printer = System.err.println
    printer: String => Unit = $$Lambda$1092/1353172779@54c11750
    
    scala> printer("Test printer")
    Test printer
    
    • References to methods can also be stored in variables of function type. In this example, the variable action stores a reference to the method _.showInventory of an instance of the class ProductInventory.
    scala> var action: () => Unit = () => ()
    action: () => Unit
    
    scala> action()
    
    
    scala> val printMe = () => println("Print me right now")
    printMe: () => Unit
    
    scala> action = printMe
    action: () => Unit 
    
    scala> action()
    Print me right now
    
    object Utils{
      def showLinuxRootFiles() =
        for(f <- new java.io.File("/").listFiles)
          println(f)
    }
    
    
    scala> action = Utils.showLinuxRootFiles _
    action: () => Unit 
    
    scala> action()
    /etc
    /tmp
    /sbin
    /sys
    /opt
    /media
    /boot
     ... ... ... ... ... ... ... ...
    
    
    class ProductInventory{
      private val lst = new java.util.ArrayList[String]
    
      def addProduct(product: String) = {
        println("Logger -> Added " + product)    
        lst.add(product)
      }
    
      def showInventory() =
        lst.forEach{ p => println("Product = " + p)}
    }
    
    
    
    scala> val myShopInventory = new ProductInventory()
    myShopInventory: ProductInventory = ProductInventory@5a6dbab7
    
    scala> myShopInventory.addProduct("Orange")
    Logger -> Added Orange
    res11: Boolean = true
    
    scala> myShopInventory.addProduct("Apple")
    Logger -> Added Apple
    res12: Boolean = true
    
    scala> myShopInventory.addProduct("Coffee beans")
    Logger -> Added Coffee beans
    res13: Boolean = true
    
    scala> myShopInventory.showInventory()
    Product = Orange
    Product = Apple
    Product = Coffee beans
    
    scala> action = myShopInventory.showInventory _
    action: () => Unit = $$Lambda$1369/801054059@4f4a6252
    
    scala> action()
    Product = Orange
    Product = Apple
    Product = Coffee beans
    
    scala> myShopInventory.addProduct("Strawberry")
    Logger -> Added Strawberry
    res18: Boolean = true
    
    scala> action()
    Product = Orange
    Product = Apple
    Product = Coffee beans
    Product = Strawberry
    
    • Store functions in arrays, hash maps (dictionaries) and lists:
    // Dummy - do anything 
    scala> val action0 = () => ()
    action0: () => Unit = $$Lambda$1375/1357073725@74ddf6f8
    
    scala> val action1 = () => println("Get product from inventory")
    action1: () => Unit = $$Lambda$1373/1589324702@6bfa9cf5
    
    scala> val action2 = () => println("Order more replacement parts from the manufacturer X inc.")
    action2: () => Unit = $$Lambda$1374/180387583@1c9eb283
    
    def action3() = 
      println("Check company's balance sheet.")
    
    class CompanyData(name: String){
      def printStatements() = {
        println("Print Balance Sheet of company       = " + name)
        println("Print Cash Flow statement of company = " + name)
      }
    }
    
    scala> val company = new CompanyData("XZYZW Solution. Inc.")
    company: CompanyData = CompanyData@249318e7
    
    //------ Register functions --------------- //
    
    scala> import scala.collection.mutable.ListBuffer
    import scala.collection.mutable.ListBuffer
    
    scala> val actionList = ListBuffer[() => Unit]()
    actionList: scala.collection.mutable.ListBuffer[() => Unit] = ListBuffer()
    
    scala> actionList.append(action0)
    scala> actionList.append(action1)
    scala> actionList.append(action2)
    
    scala> for (act <- actionList) act()
    Get product from inventory
    Order more replacement parts from the fanufacterer X inc.
    
    actionList.append(action3 _)
    
    scala> for (act <- actionList) act()
    Get product from inventory
    Order more replacement parts from the fanufacterer X inc.
    Check company's balance sheet.
    
    // Register method to be called 
    scala> actionList.append(company.printStatements _)
    
    scala> for (act <- actionList) act()
    Get product from inventory
    Order more replacement parts from the fanufacterer X inc.
    Check company's balance sheet.
    Print Balance Sheet of company       = XZYZW Solution. Inc.
    Print Cash Flow statement of company = XZYZW Solution. Inc.
    

    1.4.10 Variadic - function or functions with variable number of arguments:

    Basic example:

    def varfun(inputs: String*) = {
      println("I got the parameters: ")
      inputs.foreach(println)
    }
    
    scala> varfun("Hello", "World", "Scala", "Rocks")
    I got the parameters:
    Hello
    World
    Scala
    Rocks
    

    Pass collections as arguments of variadic functions:

    scala> val xs = List("hello", "World", "Scala", "Rocks")
    xs: List[String] = List(hello, World, Scala, Rocks)
    
    scala> varfun(xs)
    <console>:14: error: type mismatch;
     found   : List[String]
     required: String
           varfun(xs)
                  ^
    
    scala> varfun(xs : _ *)
    I got the parameters: 
    hello
    World
    Scala
    Rocks
    
    scala> val xs2  = Vector("Java", "everywhere", "in", "desktop", "servers", "mobile")
    xs2: scala.collection.immutable.Vector[String] = Vector(Java, everywhere, in, desktop, servers, mobile)
    
    scala> varfun(xs2 :_ *)
    I got the parameters: 
    Java
    everywhere
    in
    desktop
    servers
    mobile
    

    1.4.11 Functions with default parameters

    /** Free fall speed v(t) = g * t, g in m/s^2 */
    def freeFallSpeed(time: Double, gravity: Double = 9.81) = time * gravity
    
    scala> freeFallSpeed(1.0)
    res30: Double = 9.81
    
    scala> freeFallSpeed(2.0)
    res31: Double = 19.62
    
    scala> freeFallSpeed(2.0, 10.0)
    res32: Double = 20.0
    
    scala> freeFallSpeed(2.0, 20.0)
    res33: Double = 40.0
    
    scala> freeFallSpeed(2.0, gravity = 10.0)
    res35: Double = 20.0
    
    scala> freeFallSpeed(2.0, gravity = 15.0)
    res36: Double = 30.0
    

    1.4.12 Functions with call-by-name parameters

    1.4.12.1 call-by-value or pass-by-value

    In Scala function parameters are passed by value by default. They are evaluated before function application.

    scala> val rnd = new java.util.Random()
    rnd: java.util.Random = java.util.Random@3198594d
    
    def passByValue(x: Int) = List(x, x, x)
    
    scala> passByValue(rnd.nextInt(10))
    res31: List[Int] = List(2, 2, 2)
    
    scala> passByValue(rnd.nextInt(10))
    res32: List[Int] = List(1, 1, 1)
    
    scala> rnd.nextInt(10)
    res12: Int = 2
    
    scala> rnd.nextInt(10)
    res13: Int = 3
    
    scala> rnd.nextInt(10)
    res14: Int = 4
    
    1.4.12.2 call-by-name or pass-by-name

    In the call-by-name evaluation strategy the function parameter passed by name is not evaluated before the function application such as in the pass-by-value strategy and they are evaluated every time they are referenced.

    Example 1: The parameter x is passed-by-name and it is evaluated every time it appears in the function body as the expression rnd.nextInt(10).

    def passByName(x: => Int) = List(x, x, x)
    
    scala> passByName(rnd.nextInt(10))
    res33: List[Int] = List(7, 8, 7)
    
    scala> passByName(rnd.nextInt(10))
    res34: List[Int] = List(6, 4, 0)
    
    scala> passByName{rnd.nextInt(10)}
    res35: List[Int] = List(7, 4, 8)
    
    scala> passByName{rnd.nextInt(10)}
    res36: List[Int] = List(5, 9, 8)
    

    It is equivalent to:

    def passByNameSimulation(x: () => Int) = List(x(), x(), x())
    
    scala> passByNameSimulation(() => rnd.nextInt(10))
    res37: List[Int] = List(7, 4, 0)
    
    scala> passByNameSimulation(() => rnd.nextInt(10))
    res38: List[Int] = List(2, 6, 1)
    
    scala> passByNameSimulation(() => rnd.nextInt(10))
    res39: List[Int] = List(1, 0, 7)
    

    Example 2:

    def do3Times(fn: => Unit){ fn ; fn ; fn }
    
    scala> do3Times{ println("Hello world") }
    Hello world
    Hello world
    Hello world
    
    1.4.12.3 Custom control structures with call-by-name

    Pass-by-name parameters are useful for implementing functions that works like custom control structures and to pass code blocks as function parameters.

    Example 1: Some custom "control structures".

    def dotimes(n: Int)(fn: => Unit){
      for (i <- 1 to n) fn
    }
    
    dotimes(3){
      println("Scala is amazing.")
      println("Scala's super powers.\n")
    }
    
    scala> dotimes(3){
         |   println("Scala is amazing.")
         |   println("Scala's super powers.\n")
         | }
    Scala is amazing.
    Scala's super powers.
    
    Scala is amazing.
    Scala's super powers.
    
    Scala is amazing.
    Scala's super powers.
    
    
    def doWhile(cond: => Boolean)(fn: => Unit){
      fn 
      if (cond) doWhile{cond}{fn}
    }
    
    var x = 5
    doWhile(x > 0){
      println("x = " + x)
      x = x - 1 
    }
    
    scala> var x = 5
    x: Int = 5
    
    scala> doWhile(x > 0){
         |   println("x = " + x)
         |   x = x - 1 
         | }
    x = 5
    x = 4
    x = 3
    x = 2
    x = 1
    
    
    // delay in mili seconds. 
    def doAfterDelay(delay: Int)(action: => Unit) = {
      java.lang.Thread.sleep(delay)
      action
    }
    
    scala> doAfterDelay(2000){ println("2 seconds delay") }
    2 seconds delay
    
    
    def loopDelay(delay: Int)(action: => Unit) {
      java.lang.Thread.sleep(delay)
      action
      loopDelay(delay){action}
    }
    
    scala> loopDelay(1000){ println("Print it forever every 1 second") } 
    Print it forever every 1 second
    Print it forever every 1 second
    Print it forever every 1 second
    Print it forever every 1 second
    
    ... ... ...
    

    Example 2: Passing code blocks as java swing event handlers.

    /** Function that when executed removes the event handler */
    type Dispose = () => Unit
    
    /** Subscribes to button click event */
    def onButtonClick(button: javax.swing.JButton) (handler: => Unit) : Dispose = {
      val listener = new java.awt.event.ActionListener(){
        def actionPerformed(evt: java.awt.event.ActionEvent) = {
          handler
        }
      }
      button.addActionListener(listener)
      // Returns function that when executed disposes the event handler 
      () => button.removeActionListener(listener)
      }
    
    
    var n = 0 
    
    val frame  = new javax.swing.JFrame("Click on the button")
    val panel  = new javax.swing.JPanel()
    val button = new javax.swing.JButton("Click me right now!")
    val label  = new javax.swing.JLabel(s"I was clicked ${n} times.")
    
    panel.add(button)
    panel.add(label)
    frame.add(panel)
    frame.setSize(300, 400)
    frame.setVisible(true)
    
    
    val dispose1 = onButtonClick(button){
      println(s"The user clicked the button ${n} times.")
      label.setText(s"I was clicked ${n} times.")
      n = n + 1
    }
    
    scala> val dispose1 = onButtonClick(button){
         |   println(s"The user clicked the button ${n} times.")
         |   label.setText(s"I was clicked ${n} times.")
         |   n = n + 1
         | }
    dispose1: Dispose = <function0>
    
    // Run dispose1 to remove event handler.
    scala> dispose1()
    

    1.4.13 Singleton or Module

    A singleton object is an object of a class with a single instance implementing the singleton design pattern. A singletion object can be used as an ML-module which is a container for grouping functions.

    cala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    
    object Module {
    
      val code = "xyzfmnk"
    
      var amount = 1000 
    
      def sayHello () = println("Hello world")
    
      def fn(x: Int, y: Int) = 3 * x + 4 * y
    
      def showFiles(path: String) = {
        val files = (new java.io.File(path)).listFiles().filter(_.isFile)
        files.foreach(println)    
      }
    
      def showDirectories(path: String) = {
        val files = (new java.io.File(path)).listFiles().filter(_.isDirectory)
        files.foreach(println)    
      }
    
    }
    
    scala> Module.fn _
    res204: (Int, Int) => Int = <function2>
    
    scala> Module.sayHello _
    res205: () => Unit = <function0>
    
    scala> Module.showFiles _
    res206: String => Unit = <function1>
    
    scala> Module.showFiles("/boot")
    /boot/initramfs-3.10-x86_64.img
    /boot/vmlinuz-4.9-x86_64
    /boot/initramfs-3.10-x86_64-fallback.img
    /boot/vmlinuz-3.10-x86_64
    /boot/initramfs-4.9-x86_64-fallback.img
    /boot/initramfs-4.9-x86_64.img
    /boot/intel-ucode.img
    /boot/linux310-x86_64.kver
    /boot/linux49-x86_64.kver
    
    scala> Module.showDirectories("/boot/grub")
    /boot/grub/i386-pc
    /boot/grub/locale
    /boot/grub/fonts
    /boot/grub/themes
    
    scala> Module.sayHello()
    Hello world
    
    scala> Module.code 
    res219: String = xyzfmnk
    
    scala> Module.code = "hello"
    <console>:13: error: reassignment to val
           Module.code = "hello"
                       ^
    
    scala> Module.amount += 300
    
    scala> Module.amount
    res223: Int = 1300
    
    
    scala> Module.amount = 0
    Module.amount: Int = 0
    
    scala> Module.getClass()
    res224: Class[_ <: Module.type] = class Module$
    

    Singletons can implement interfaces or traits.

    trait Observer{
      def onChange(): Unit
      def onError():  Unit  
    }
    
    class Observer1 extends Observer{
      def onChange() =
        println("I received a change event.")
    
      def onError() =
        println("I received an error event.")
    }
    
    object SingleTonObserver extends Observer{
      def onChange() =
        println("Singleton: I received a change event.")
    
      def onError() =
        println("Singleton: I received an error event.")
    }
    
    scala> obs1.onChange()
    I received a change event.
    
    scala> obs1.onError()
    I received an error event.
    
    scala> SingleTonObserver.onChange()
    Singleton: I received a change event.
    
    scala> SingleTonObserver.onError()
    Singleton: I received an error event.
    
    def generateErrorEvent(obs: Observer) =
      obs.onError()
    
    scala> generateErrorEvent(obs1)
    I received an error event.
    
    scala> generateErrorEvent(SingleTonObserver)
    Singleton: I received an error event.
    

    1.5 Imperative Constructs

    1.5.1 While loop

    var i = 0
    while (i < 10){
       println ("i = " + i)
       i = i + 1
    }
    
    scala> var i = 0
    i: Int = 0
    
    scala> while (i < 10){
         |    println ("i = " + i)
         |    i = i + 1
         | }
    i = 0
    i = 1
    i = 2
    i = 3
    i = 4
    i = 5
    i = 6
    i = 7
    i = 8
    i = 9
    

    1.5.2 Do-while loop

    val fr  = new java.io.FileReader("/etc/protocols")
    val bfr = new java.io.BufferedReader(fr)
    val maxLines = 15
    var line = ""
    var n = 0 
    
    do{
      line = bfr.readLine()
      println(s"Line $n = " + line)
      n = n + 1
    } while(line != null && n < maxLines)
    
    println(s"Number of lines read is equal to $n ")
    
    fr.close()
    bfr.close()
    

    Output:

    scala> do{
         |   line = bfr.readLine()
         |   println(s"Line $n = " + line)
         |   n = n + 1
         | } while(line != null && n < maxLines)
    Line 0 = # /etc/protocols:
    Line 1 = # $Id: protocols,v 1.12 2016/07/08 12:27 ovasik Exp $
    Line 2 = #
    Line 3 = # Internet (IP) protocols
    Line 4 = #
    Line 5 = #  from: @(#)protocols 5.1 (Berkeley) 4/17/89
    Line 6 = #
    Line 7 = # Updated for NetBSD based on RFC 1340, Assigned Numbers (July 1992).
    Line 8 = # Last IANA update included dated 2011-05-03
    Line 9 = #
    Line 10 = # See also http://www.iana.org/assignments/protocol-numbers
    Line 11 = 
    Line 12 = ip    0   IP      # internet protocol, pseudo protocol number
    Line 13 = hopopt    0   HOPOPT      # hop-by-hop options for ipv6
    Line 14 = icmp  1   ICMP        # internet control message protocol
    
    scala> println(s"Number of lines read is equal to $n ")
    Number of lines read is equal to 15
    

    1.5.3 For-loop

    Note: Scala's for-loop is not equivalent to the Java's for-loop, it is actually a syntax sugar for the method .foreach, so the Scala's for-loop has a performance overhead which may be significant for numerical or array operations. In this case the primitive while loop is faster and equivalent to the Java's for-loop.

    scala> for (i <- 1 to 10) println(i)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    scala> for (i <- 1 to 10) println("i = " + i)
    i = 1
    i = 2
    i = 3
    i = 4
    i = 5
    i = 6
    i = 7
    i = 8
    i = 9
    i = 10
    
    scala> for (file <- (new java.io.File("/").listFiles)) println(file)
    /home
    /var
    /bin
    /usr
    /root
    /Applications
    /proc
    /boot
    /dev
    /opt
    /etc
    /mnt
    /tmp
    /run
    /desktopfs-pkgs.txt
    /lib
    /.manjaro-tools
    /srv
    /lib64
    /rootfs-pkgs.txt
    /sys
    /sbin
    /lost+found
    

    1.6 String Manipulation

    1.6.1 Basic string operations

    @ val s = "  Hello world scala  "  
    s: String = "  Hello world scala  "
    

    Get string length

    @ s.size 
    res41: Int = 21
    @  
    @ s size 
    res42: Int = 21
    @  
    @ s.length 
    res43: Int = 21
    
    @ s length 
    res44: Int = 21
    @
    

    Concatenate string

    @ "Hello" + " " + "world" + " " + "scala" 
    res45: String = "Hello world scala"
    @
    

    Trim

    @ s  
    res47: String = "  Hello world scala  "
    @ s trim 
    res48: String = "Hello world scala"
    @ s.trim() 
    res49: String = "Hello world scala"
    @ s trim  
    res50: String = "Hello world scala"
    @
    

    Replace string

    @ s.replace("scala", "haskell") 
    res46: String = "  Hello world haskell  "
    @
    

    Upper and lower case

    @ s.toUpperCase 
    res60: String = "  HELLO WORLD SCALA  "
    
    @ s.toLowerCase 
    res61: String = "  hello world scala  "
    @
    

    Check if string starts with prefix

    @ "hello world".startsWith("hello") 
    res65: Boolean = true
    @  
    @ "hello world" startsWith "hello" 
    res66: Boolean = true
    @
    

    Check if string ends with suffix

    @ "hello world".endsWith("hello") 
    res67: Boolean = false
    @  
    @ "hello world".endsWith("world") 
    res68: Boolean = true
    @  
    @ "hello world" endsWith "world" 
    res69: Boolean = true
    @
    

    String equality test

    Equality checkign (==) is not type-safe due to interoperability with Java. Some libraries such as Scalaz provides a type-safe equality check operator (=).

    // Operator (==) is not type-safe: 
    //
    @ "hello" == "world" 
    res51: Boolean = false
    @ "hello" == "hello" 
    res52: Boolean = true
    
    // This inconsistent operation type checks.
    @ "hello" == 100 
    res53: Boolean = false
    @
    

    1.6.2 String Interpolation

    1.6.2.1 Example 1
    scala> val x = 10.24
    x: Double = 10.24
    
    scala> val y = 2.5413
    y: Double = 2.5413
    
    scala> val text = s"The value of x is $x and the value of y is $y, the sum of x + y = ${x + y}"
    text: String = The value of x is 10.24 and the value of y is 2.5413, the sum of x + y = 12.7813
    
    @ "the value of square root of %.3f is equal to %.3f".format(10.0, Math.sqrt(10.0)) 
    res70: String = "the value of square root of 10.000 is equal to 3.162"
    @  
    
    @ printf("the value of square root of %.3f is equal to %.3f\n", 10.0, Math.sqrt(10.0)) 
    the value of square root of 10.000 is equal to 3.162
    
    @ "Sum of array = %d".format(sum(Array(1, 2, 3, 4))) 
    res78: String = "Sum of array = 10"
    @
    
    1.6.2.2 Example 2
    @ val xs = List(1, 2, 3, 4, 5) 
    xs: List[Int] = List(1, 2, 3, 4, 5)
    @  
    @ val str = "hello world" 
    str: String = "hello world"
    @  
    @ s"xs = ${xs} ; sum(xs) = ${xs sum} ; str = '${str}' ; size(str) = ${str size} " 
    res86: String = "xs = List(1, 2, 3, 4, 5) ; sum(xs) = 15 ; str = 'hello world' ; size(str) = 11 "
    @
    

    1.6.3 Join multiple strings by common separators

    scala> List("Oversee", "fixed", "income", "assets").mkString(", ")
    res11: String = Oversee, fixed, income, assets
    
    scala> List("Oversee", "fixed", "income", "assets") mkString " "
    res12: String = Oversee fixed income assets
    
    scala> Vector("Oversee", "fixed", "income", "assets") mkString " "
    res13: String = Oversee fixed income assets
    
    scala> Array("Oversee", "fixed", "income", "assets") mkString ":"
    res14: String = Oversee:fixed:income:assets
    
    scala> xs.mkString(", ")
    res15: String = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    
    scala> xs.mkString("; ")
    res16: String = 1; 2; 3; 4; 5; 6; 7; 8; 9; 10
    
    scala> val rootDir = new java.io.File("/").listFiles().mkString("\n => ")
    rootDir: String =
    /etc
     => /tmp
     => /sbin
     => /sys
     => /opt
     => /media
     => /boot
     => /.local
     => /.autorelabel
     => /home
    

    1.6.4 String conversion

    String to Boolean

    scala> "true".toBoolean
    res27: Boolean = true
    
    scala> "false".toBoolean
    res28: Boolean = false
    
    scala> "f".toBoolean
    java.lang.IllegalArgumentException: For input string: "f"
      at scala.collection.immutable.StringLike.parseBoolean(StringLike.scala:324)
    

    String to signed Byte (8 bits from -128 to 127)

    scala> "-128".toByte
    res37: Byte = -128
    
    scala> "127".toByte
    res38: Byte = 127
    
    scala> "128".toByte
    java.lang.NumberFormatException: Value out of range. Value:"128" Radix:10
      at java.lang.Byte.parseByte(Byte.java:151)
    
    scala> "1df28".toByte
    java.lang.NumberFormatException: For input string: "1df28"
      at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
      at java.lang.Integer.parseInt(Integer.java:580)
      at java.lang.Byte.parseByte(Byte.java:149)
      at java.lang.Byte.parseByte(Byte.java:175)
    

    String to Int

    scala> "200".toInt
    res11: Int = 200
    
    scala> "200".toInt * 3
    res4: Int = 600
    
    scala> 3 * "200".toInt 
    res5: Int = 600
    
    scala> 3 * "2ac00".toInt 
    java.lang.NumberFormatException: For input string: "2ac00"
    .... ...
    

    String to Long (64 bits Integer)

    scala> "100".toLong
    res24: Long = 100
    
    scala> "100fail!".toLong
    java.lang.NumberFormatException: For input string: "100fail!"
      at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
      at java.lang.Long.parseLong(Long.java:589)
    ... ...
    

    String to Float (32-bits IEEE Float Point)

    scala> "100".toFloat
    res21: Float = 100.0
    
    scala> "100a".toFloat
    java.lang.NumberFormatException: For input string: "100a"
      at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
      at sun.misc.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
      at java.lang.Float.parseFloat(Float.java:451)
    

    String to Double (64-bits IEEE Float Point)

    scala> "300".toDouble
    res7: Double = 300.0
    
    scala> "300" toDouble
    res8: Double = 300.0
    
    scala> Math.log10("100".toDouble)
    res10: Double = 2.0
    
    scala> Math.log10("100It is gonna fail!".toDouble)
    java.lang.NumberFormatException: For input string: "100It is gonna fail!"
      at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
      at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
      at java.lang.Double.parseDouble(Double.java:538)
      at scala.collection.immutable.StringLike.toDouble(StringLike.scala:318)
      at scala.collection.immutable.StringLike.toDouble$(StringLike.scala:318)
      at scala.collection.immutable.StringOps.toDouble(StringOps.scala:29)
      ... 29 elided
    

    1.6.5 Regex - Regular Expressions

    1.6.5.1 Pattern Matching Regex
    scala> val dateRegex = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
    dateRegex: scala.util.matching.Regex = (\d\d\d\d)-(\d\d)-(\d\d)
    
    
    
    "2010-10-15" match {
      case dateRegex(_*) => "It matches the date regex."
    }
    
    scala> "2010-10-15" match {
         |   case dateRegex(_*) => "It matches the date regex."
         | }
    res1: String = It matches the date regex.
    
    
    
    "2010-10-15" match {
      case dateRegex(y, m, d) => s"The year = $y month = $m day = $d"
    }
    
    scala> "2010-10-15" match {
         |   case dateRegex(y, m, d) => s"The year = $y month = $m day = $d"
         | }
    res0: String = The year = 2010 month = 10 day = 15
    
    1.6.5.2 Extracting Regex
    scala> val dateRegex = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
    dateRegex: scala.util.matching.Regex = (\d\d\d\d)-(\d\d)-(\d\d)
    
    scala> val dateRegex(y, m, d) = "2010-10-15"
    y: String = 2010
    m: String = 10
    d: String = 15
    
    scala> y
    res2: String = 2010
    
    scala> m
    res3: String = 10
    
    scala> d
    res4: String = 15
    
    scala> m.toInt + 2
    res5: Int = 12
    
    scala> s"The year = $y month = $m day = $d"
    res6: String = The year = 2010 month = 10 day = 15
    
    scala> println(s"The year = $y month = $m day = $d")
    The year = 2010 month = 10 day = 15
    
    1.6.5.3 Find all strings that matching a regex
    val dateRegex = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
    
    scala> val dateList = "2004-01-20 1998-02-12  2003-04-15"
    dateList: String = 2004-01-20 1998-02-12  2003-04-15
    
    scala> dateRegex.findFirstIn(dateList)
    res6: Option[String] = Some(2004-01-20)
    
    scala> m.next
    res9: scala.util.matching.Regex.Match = 2004-01-20
    
    scala> m.next
    res10: scala.util.matching.Regex.Match = 1998-02-12
    
    scala> m.next
    res11: scala.util.matching.Regex.Match = 2003-04-15
    
    scala> m.hasNext
    res12: Boolean = false
    
    scala> m.next
    java.util.NoSuchElementException
      at scala.util.matching.Regex$MatchIterator.next(Regex.scala:753)
      at scala.util.matching.Regex$$anon$4.next(Regex.scala:374)
      at scala.util.matching.Regex$$anon$4.next(Regex.scala:371)
        ... 32 elided
    
    
    scala> val m = dateRegex.findAllMatchIn(dateList)
    m: Iterator[scala.util.matching.Regex.Match] = non-empty iterator
    
    scala> m.toList
    res14: List[scala.util.matching.Regex.Match] = List(2004-01-20, 1998-02-12, 2003-04-15)
    
    1.6.5.4 Replace text
    scala> val dateRegex = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
    dateRegex: scala.util.matching.Regex = (\d\d\d\d)-(\d\d)-(\d\d)
    
    scala> val dateList = "2004-01-20 1998-02-12  2003-04-15"
    dateList: String = 2004-01-20 1998-02-12  2003-04-15
    
    scala> dateRegex.replaceAllIn(dateList, "xxxx-xx-xx")
    res16: String = xxxx-xx-xx xxxx-xx-xx  xxxx-xx-xx
    
    1.6.5.5 Regex use case for extracting color from string
    val rgbRegex = """rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)""".r
    
    def getColor(color: String) = color match {
      case "blue"    => java.awt.Color.blue
      case "cyan"    => java.awt.Color.cyan
      case "red"     => java.awt.Color.red
      case "green"   => java.awt.Color.green
      case "yellow"  => java.awt.Color.yellow
      case "white"   => java.awt.Color.white
      case "pink"    => java.awt.Color.pink
      case "black"   => java.awt.Color.black
      case "magenta" => java.awt.Color.magenta
      case "orange"  => java.awt.Color.orange
      case "gray"    => java.awt.Color.gray
      case rgbRegex(r, g, b) => new java.awt.Color(r.toInt, g.toInt, b.toInt)
      case  _        => throw new IllegalArgumentException("Error invalid color name.")
    }
    
    
    @ getColor("blue") 
    res2: java.awt.Color = java.awt.Color[r=0,g=0,b=255]
    @  
    @ getColor("rgb(255, 0, 0)") 
    res3: java.awt.Color = java.awt.Color[r=255,g=0,b=0]
    @  
    @ getColor("rgb(10, 121, 25)") 
    res4: java.awt.Color = java.awt.Color[r=10,g=121,b=25]
    @  
    @ getColor("rgb(10, 121, 25) error") 
    java.lang.IllegalArgumentException: Error invalid color name.
      ammonite.$sess.cmd1$.getColor(cmd1.sc:14)
      ammonite.$sess.cmd5$.<init>(cmd5.sc:1)
      ammonite.$sess.cmd5$.<clinit>(cmd5.sc)
    
    @ getColor("red") 
    res6: java.awt.Color = java.awt.Color[r=255,g=0,b=0]
    @  
    @ getColor("invalid color") 
    java.lang.IllegalArgumentException: Error invalid color name.
      ammonite.$sess.cmd1$.getColor(cmd1.sc:14)
      ammonite.$sess.cmd7$.<init>(cmd7.sc:1)
      ammonite.$sess.cmd7$.<clinit>(cmd7.sc)
    

    1.7 Collections

    1.7.1 Overview

    Collection Hierarchy

    • Iterable
      • Seq (Sequence)
        • List
          • Fundamental operations: head, tail
        • Vector
          • indexing
        • Array. Mutable array, equivalent to Java Array.
        • String (Seq-like, although not subclass of Seq).
        • Range
      • Sets (Relational algebra). Contains no duplicated element.
      • Map (aka Hashmap, Dictionary or hash-table)
    Scala Collection Description Immutable
    List Linked list Yes
    Iterable / Stream Lazy evaluation Yes
    Array Random Access by index No
    Map Hash table / Dictionary, Index table Yes
    Set Unique items Yes
         

    1.7.2 Immutable Collections

    1.7.2.1 Tuples
    1.7.2.2 List

    Creating a list

    scala> var xs = List(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
    xs: List[Double] = List(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)
    

    Map over a list

    scala> xs.map (x => x * 3.0)
    res31: List[Double] = List(3.0, 6.0, 9.0, 12.0, 15.0, 18.0)
    
    scala> xs.map (x => x * 3.0).map (x => x + 5)
    res33: List[Double] = List(8.0, 11.0, 14.0, 17.0, 20.0, 23.0)
    

    Filter a list

    // Filter
    //
    scala> xs.filter ( x => x < 4.0)
    res30: List[Double] = List(1.0, 2.0, 3.0)
    

    Filter a list / reject

    // FilterNot - Inverse of filter, reject
    //
    scala> xs.filterNot (x => x < 4.0)
    res80: List[Double] = List(4.0, 5.0, 6.0)
    

    Find a element that matches a predicate function

    // Find the first element that satisfies
    // a predicate.
    //
    //
    scala> xs.find _
    res43: (Double => Boolean) => Option[Double] = <function1>
    
    
    scala> xs.find (x => x > 4.0)
    res42: Option[Double] = Some(5.0)
    
    scala> xs.find (x => x > 14.0)
    res44: Option[Double] = None
    

    Test if list is empty

    // Test if list is empty
    //
    scala> xs.isEmpty
    res85: Boolean = false
    

    Find the index of an element that satisfies a predicate

    // Find the index of an element that satisfies a predicate.
    //
    //
    scala> xs.indexWhere (x =>  x > 4.0)
    res116: Int = 4
    
    scala> xs.indexWhere (x =>  x > 14.0)
    res117: Int = -1
    

    Count all elements that matches a predicate

    // Count all elements greater than 3.0
    //
    scala> xs.count (x => x > 3.0)
    res18: Int = 3
    

    Get max and min elements

    // Max and Min elements
    //
    scala> xs.max
    res19: Double = 6.0
    
    scala> xs.min
    res20: Double = 1.0
    

    Head (fist) and (last) elements

    // Head and tail of a list.
    
    // First element
    scala> xs.head
    res21: Double = 1.0
    
    // Last element
    scala> xs.last
    res45: Double = 6.0
    

    Tail

    //
    // Tail: Remove first element
    scala> xs.tail
    res22: List[Double] = List(2.0, 3.0, 4.0, 5.0, 6.0)
    

    Reverse a list

    scala> xs.reverse
    res36: List[Double] = List(6.0, 5.0, 4.0, 3.0, 2.0, 1.0)
    

    Foreach

    // Impure Map
    //
    scala> xs.foreach(println)
    1.0
    2.0
    3.0
    4.0
    5.0
    6.0
    
    scala> xs.foreach(x => println( "x = %.3f".format(x)))
    x = 1,000
    x = 2,000
    x = 3,000
    x = 4,000
    x = 5,000
    x = 6,000
    

    Slice elements

    // Select elements x[2],x[3] and x[4]
    //
    scala> xs.slice(2, 5)
    res40: List[Double] = List(3.0, 4.0, 5.0)
    

    Take n elements

    scala> xs.take(3)
    res68: List[Double] = List(1.0, 2.0, 3.0)
    

    Drop elements

    // Drop elements
    //
    scala> xs.drop _
    res66: Int => List[Double] = <function1>
    
    scala> xs.drop (3)
    res67: List[Double] = List(4.0, 5.0, 6.0)
    

    Length of a list

    // Length of a list
    //
    scala> xs.length
    res69: Int = 6
    

    Sum of all list elements

    // Sum of all elements of a list
    //
    scala> xs.sum
    res82: Double = 21.0
    

    Product of all list elements

    // Product of all elements of a list
    //
    scala> xs.product
    res83: Double = 720.0
    

    Fold left

    // Fold left
    //
    scala> List(1, 2, 3, 4, 5).foldLeft(0)((acc, x) => 100 * acc + x)
    res107: Int = 102030405
    
    scala> List(1, 2, 3, 4, 5).foldLeft(List[Int] ())((acc, x) => x :: acc)
    res110: List[Int] = List(5, 4, 3, 2, 1)
    

    Fold right

    // Fold right
    //
    scala> List(1, 2, 3, 4, 5).foldRight(0)((x, acc) => 10 * acc + x)
    res111: Int = 54321
    

    Reduce

    // Reduce. fold left without initial value of accumulator.
    scala> xs.reduce _
    res92: ((Double, Double) => Double) => Double = <function1>
    
    scala> xs.reduce ((acc, x) => 10*acc + x)
    res95: Double = 123456.0
    

    Max by

    // Returns the element for which the projection function has the
    // maximun value
    //
    // In this case: returns the string which its lenght is maximun.
    //
    scala> var s = List("Hello", "World", "Scala", "is", "amazing")
    s: List[String] = List(Hello, World, Scala, is, amazing)
    
    scala> s.maxBy (x => x.length)
    res74: String = amazing
    

    Min by

    //
    //  In this case: returns the string which its length is minimun.
    //
    scala> s.minBy (x => x.length)
    res75: String = is
    

    Sort by

    // Sort the string by the length of each string
    //
    scala> s.sortBy ( x => x.length)
    res78: List[String] = List(is, Hello, World, Scala, amazing)
    

    Group by

    //  groupBy
    // Separate string that have equal number of characters
    //
    scala> s.groupBy(x => x.length)
    res0: scala.collection.immutable.Map[Int,List[String]] = Map(2 -> List(is), 5 -> List(Hello, World, Scala), 7 -> List(amazing))
    
    
    def fileExtension (filename: String) = {
        val arr = filename.split ('.');
    
        if (arr.length > 1) {
           arr.apply(1);
        }else{
           "";
        }
    }
    
    var files =
    List("file1.pdf",
         "file2.doc",
         "dummy.pdf",
         "clojure.jar",
         "document.zip",
         "file3.pdf",
         "scala.jar",
         "manifest.doc",
         "unixBsd"
         )
    
    scala> files.groupBy (fileExtension)
    res17: scala.collection.immutable.Map[String,List[String]]
    = Map("" -> List(unixBsd), zip -> List(document.zip),
    pdf -> List(file1.pdf, dummy.pdf, file3.pdf),
    doc -> List(file2.doc, manifest.doc),
    jar -> List(clojure.jar, scala.jar))
    
    
    scala> files.groupBy (fileExtension).foreach(println)
    (,List(unixBsd))
    (zip,List(document.zip))
    (pdf,List(file1.pdf, dummy.pdf, file3.pdf))
    (doc,List(file2.doc, manifest.doc))
    (jar,List(clojure.jar, scala.jar))
    

    Distinct

    // Distinct elements.
    //
    scala> var a = List(1, 2, 5, 3, 1, 3, 3, 5, 4, 5, 4)
    a: List[Int] = List(1, 2, 5, 3, 1, 3, 3, 5, 4, 5, 4)
    
    scala> a.distinct
    res88: List[Int] = List(1, 2, 5, 3, 4)
    
    1.7.2.3 Maps

    Scala Maps are immutable hash tables or dictionaries.

    var capital = Map("US"     -> "Washigton",
                      "France" -> "Paris",
                      "Japan"  -> "Tokyo")
    
    scala> capital("Japan")
    res8: String = Tokyo
    
    scala> capital("US")
    res9: String = Washigton
    
    scala> capital("USsa")
    java.util.NoSuchElementException: key not found: USsa
      at scala.collection.MapLike$class.default(MapLike.scala:228)
      at scala.collection.AbstractMap.default(Map.scala:59)
      at scala.collection.MapLike$class.apply(MapLike.scala:141)
      at scala.collection.AbstractMap.apply(Map.scala:59)
      ... 32 elided
    
    
    scala> assert(capital("Japan") == "Tokyo")
    
    scala> assert(capital("Japan") == "Tokyo2")
    java.lang.AssertionError: assertion failed
      at scala.Predef$.assert(Predef.scala:156)
      ... 32 elided
    
    scala> println(capital("France"))
    Paris
    
    scala> println(capital("Japan"))
    Tokyo
    
    def getFileExtension(file: String) = {
      val i = file.lastIndexOf('.')
      if ( i > 0)
        file.substring(i+1)
      else
        ""
    }
    
    // it creates a Map of file extensions as keys and
    // all files with given extension as values
    //
    val fileGroups = {
      (new java.io.File("/etc/"))
        .listFiles()
        .filter(_.isFile)
        .map(_.getPath)
        .groupBy(getFileExtension)
    }
    
    
    scala> val fileGroups = {
         |   (new java.io.File("/etc/"))
         |     .listFiles()
         |     .filter(_.isFile)
         |     .map(_.getPath)
         |     .groupBy(getFileExtension)
         | }
    fileGroups: scala.collection.immutable.Map[String,Array[String]] =
    Map("" -> Array(/etc/motd, /etc/gemrc, /etc/environment, /etc/gshadow,
    /etc/shadow-, /etc/fstab, /etc/rpc, /etc/passwd,
    /etc/gnome-vfs-mime-magic, /etc/passwd-, /etc/sudoers,
    /etc/anacrontab, /etc/os-release, /etc/adjtime, /etc/netconfig,
    /etc/inputrc, /etc/timezone, /etc/shadow, /etc/lsb-release,
    /etc/shells, /etc/papersize, /etc/drirc, /etc/hostname, /etc/exports,
    /etc/machine-id, /etc/group-, /etc/nanorc, /etc/hosts, /etc/group,
    /etc/mtab, /etc/securetty, /etc/services, /etc/protocols,
    /etc/gshadow-, /etc/localtime, /etc/issue, /etc/ethertypes,
    /etc/manjaro-release, /etc/yaourtrc, /etc/profile, /etc/printcap,
    /etc/crypttab), backup ->
    Array(/etc/pacman-mirrors.conf.20170402.backup), bash_logout ->
    Array(/etc/bash.bash...  scala>
    
    
    // Get all files with cfg extension 
    //
    scala> fileGroups("cfg")
    res113: Array[String] = Array(/etc/vdpau_wrapper.cfg, /etc/rc_maps.cfg)
    
    // Get all files with conf extension
    //
    cala> fileGroups("conf") res117: Array[String] =
    Array(/etc/sensors3.conf, /etc/pacman.conf, /etc/cpufreq-bench.conf,
    /etc/makepkg.conf, /etc/ld.so.conf, /etc/host.conf, /etc/healthd.conf,
    /etc/ts.conf, /etc/resolvconf.conf, /etc/logrotate.conf,
    /etc/locale.conf, /etc/request-key.conf, /etc/nscd.conf,
    /etc/dnsmasq.conf, /etc/nsswitch.conf, /etc/ntp.conf,
    /etc/updatedb.conf, /etc/dhcpcd.conf, /etc/krb5.conf,
    /etc/openswap.conf, /etc/vconsole.conf, /etc/mkinitcpio.conf,
    /etc/man_db.conf, /etc/mke2fs.conf, /etc/fuse.conf, /etc/asound.conf,
    /etc/mdadm.conf, /etc/pamac.conf, /etc/nfs.conf, /etc/nfsmount.conf,
    /etc/resolv.conf, /etc/gai.conf, /etc/pacman-mirrors.conf,
    /etc/rsyncd.conf)
    
    scala> fileGroups("wrong")
    java.util.NoSuchElementException: key not found: wrong
      at scala.collection.MapLike$class.default(MapLike.scala:228)
      at scala.collection.AbstractMap.default(Map.scala:59)
      at scala.collection.MapLike$class.apply(MapLike.scala:141)
      at scala.collection.AbstractMap.apply(Map.scala:59)
      ... 32 elided
    

    Method: .get -> Get a element with given key, returning None if not element is found.

    scala> fileGroups.get("conf")
    res119: Option[Array[String]] = Some([Ljava.lang.String;@4cb04f41)
    
    scala> fileGroups.get("conf").map(_.toList) res123:
    Option[List[String]] = Some(List(/etc/sensors3.conf, /etc/pacman.conf,
    /etc/cpufreq-bench.conf, /etc/makepkg.conf, /etc/ld.so.conf,
    /etc/host.conf, /etc/healthd.conf, /etc/ts.conf, /etc/resolvconf.conf,
    /etc/logrotate.conf, /etc/locale.conf, /etc/request-key.conf,
    /etc/nscd.conf, /etc/dnsmasq.conf, /etc/nsswitch.conf, /etc/ntp.conf,
    /etc/updatedb.conf, /etc/dhcpcd.conf, /etc/krb5.conf,
    /etc/openswap.conf, /etc/vconsole.conf, /etc/mkinitcpio.conf,
    /etc/man_db.conf, /etc/mke2fs.conf, /etc/fuse.conf, /etc/asound.conf,
    /etc/mdadm.conf, /etc/pamac.conf, /etc/nfs.conf, /etc/nfsmount.conf,
    /etc/resolv.conf, /etc/gai.conf, /etc/pacman-mirrors.conf,
    /etc/rsyncd.conf))
    
    scala> fileGroups.get("confx")
    res125: Option[Array[String]] = None
    

    Method: .head -> Get first element of Map

    scala> fileGroups.head
    
    res143: (String, Array[String]) = ("",Array(/etc/motd, /etc/gemrc,
    /etc/environment, /etc/gshadow, /etc/shadow-, /etc/fstab, /etc/rpc,
    /etc/passwd, /etc/gnome-vfs-mime-magic, /etc/passwd-, /etc/sudoers,
    /etc/anacrontab, /etc/os-release, /etc/adjtime, /etc/netconfig,
    /etc/inputrc, /etc/timezone, /etc/shadow, /etc/lsb-release,
    /etc/shells, /etc/papersize, /etc/drirc, /etc/hostname, /etc/exports,
    /etc/machine-id, /etc/group-, /etc/nanorc, /etc/hosts, /etc/group,
    /etc/mtab, /etc/securetty, /etc/services, /etc/protocols,
    /etc/gshadow-, /etc/localtime, /etc/issue, /etc/ethertypes,
    /etc/manjaro-release, /etc/yaourtrc, /etc/profile, /etc/printcap,
    /etc/crypttab))
    

    Method: .last -> Get last element of Map

    scala> fileGroups.last
    
    res145: (String, Array[String]) = (defs,Array(/etc/login.defs))
    

    Method: .key -> Get all keys

    // Get all  file extensions 
    scala> fileGroups.keys
    res114: Iterable[String] = Set("", backup, bash_logout, local, pacnew, lock, conf, cache, key, shutdown, updated, cfg, deny, bashrc, types, rc, gen, defs)
    
    // Print all file extensions 
    scala> fileGroups.keys.foreach(println)
    
    backup
    bash_logout
    local
    pacnew
    lock
    conf
    cache
    key
    shutdown
    updated
    cfg
    deny
    bashrc
    types
    rc
    gen
    defs
    

    Method: .values -> Get all values.

    scala> fileGroups.values
    res126: Iterable[Array[String]] = MapLike(Array(/etc/motd, /etc/gemrc,
    /etc/environment, /etc/gshadow, /etc/shadow-, /etc/fstab, /etc/rpc,
    /etc/passwd, /etc/gnome-vfs-mime-magic, /etc/passwd-, /etc/sudoers,
    /etc/anacrontab, /etc/os-release, /etc/adjtime, /etc/netconfig,
    /etc/inputrc, /etc/timezone, /etc/shadow, /etc/lsb-release,
    /etc/shells, /etc/papersize, /etc/drirc, /etc/hostname, /etc/exports,
    /etc/machine-id, /etc/group-, /etc/nanorc, /etc/hosts, /etc/group,
    /etc/mtab, /etc/securetty, /etc/services, /etc/protocols,
    /etc/gshadow-, /etc/localtime, /etc/issue, /etc/ethertypes,
    /etc/manjaro-release, /etc/yaourtrc, /etc/profile, /etc/printcap,
    /etc/crypttab), Array(/etc/pacman-mirrors.conf.20170402.backup),
    Array(/etc/bash.bash_logout), Array(/etc/rc.local),
      Array(/etc/pacman-mirrors.co...  scala>
    
    scala> fileGroups.values.head
    res129: Array[String] = Array(/etc/motd, /etc/gemrc, /etc/environment,
    /etc/gshadow, /etc/shadow-, /etc/fstab, /etc/rpc, /etc/passwd,
    /etc/gnome-vfs-mime-magic, /etc/passwd-, /etc/sudoers,
    /etc/anacrontab, /etc/os-release, /etc/adjtime, /etc/netconfig,
    /etc/inputrc, /etc/timezone, /etc/shadow, /etc/lsb-release,
    /etc/shells, /etc/papersize, /etc/drirc, /etc/hostname, /etc/exports,
    /etc/machine-id, /etc/group-, /etc/nanorc, /etc/hosts, /etc/group,
    /etc/mtab, /etc/securetty, /etc/services, /etc/protocols,
    /etc/gshadow-, /etc/localtime, /etc/issue, /etc/ethertypes,
    /etc/manjaro-release, /etc/yaourtrc, /etc/profile, /etc/printcap,
      /etc/crypttab)
    

    Method: .size -> Get the number of Map elements or the number of key, value pairs.

    scala> fileGroups.size
    res148: Int = 18
    
    scala> fileGroups size
    res149: Int = 18
    

    Method: .mapValues -> Apply a function to each map value.

    /// Get a Map with all extension and number of files with a given extension.
    scala> fileGroups.mapValues(x => x.length)
    
    res136: scala.collection.immutable.Map[String,Int] = Map("" -> 42,
    backup -> 1, bash_logout -> 1, local -> 1, pacnew -> 1, lock -> 1,
    conf -> 34, cache -> 1, key -> 1, shutdown -> 1, updated -> 1, cfg ->
    2, deny -> 1, bashrc -> 1, types -> 1, rc -> 2, gen -> 1, defs -> 1)
    
    scala> fileGroups.mapValues(_.length)
    res137: scala.collection.immutable.Map[String,Int] = Map("" -> 42,
    backup -> 1, bash_logout -> 1, local -> 1, pacnew -> 1, lock -> 1,
    conf -> 34, cache -> 1, key -> 1, shutdown -> 1, updated -> 1, cfg ->
      2, deny -> 1, bashrc -> 1, types -> 1, rc -> 2, gen -> 1, defs -> 1)
    
    scala> fileGroups.mapValues(_.length).foreach(println)
    (,42)
    (backup,1)
    (bash_logout,1)
    (local,1)
    (pacnew,1)
    (lock,1)
    (conf,34)
    (cache,1)
    (key,1)
    (shutdown,1)
    (updated,1)
    (cfg,2)
    (deny,1)
    (bashrc,1)
    (types,1)
    (rc,2)
    (gen,1)
    (defs,1)
    

    Method: .map -> Apply a function to each to each (key, value) pair.

    scala>  fileGroups.map {case (k, v) => (k, v.length)}
    
    // Get new Map with (extension, number of files with extension)
    // pairs.
    //
    res160: scala.collection.immutable.Map[String,Int] = Map("" -> 42,
    backup -> 1, bash_logout -> 1, local -> 1, pacnew -> 1, lock -> 1,
    conf -> 34, cache -> 1, key -> 1, shutdown -> 1, updated -> 1, cfg ->
    2, deny -> 1, bashrc -> 1, types -> 1, rc -> 2, gen -> 1, defs -> 1)
    
    
    
    scala>  fileGroups.map {case (k, v) => (k, v.max)}
    
    res161: scala.collection.immutable.Map[String,String] = Map("" ->
    /etc/yaourtrc, backup -> /etc/pacman-mirrors.conf.20170402.backup,
    bash_logout -> /etc/bash.bash_logout, local -> /etc/rc.local,
    pacnew -> /etc/pacman-mirrors.conf.pacnew, lock -> /etc/.pwd.lock,
    conf -> /etc/vconsole.conf, cache -> /etc/ld.so.cache, key ->
    /etc/trusted-key.key, shutdown -> /etc/rc.local.shutdown, updated ->
    /etc/.updated, cfg -> /etc/vdpau_wrapper.cfg, deny -> /etc/cron.deny,
    bashrc -> /etc/bash.bashrc, types -> /etc/mime.types, rc ->
    /etc/slsh.rc, gen -> /etc/locale.gen, defs -> /etc/login.defs)
    

    Method: .foreach -> Apply a function that returns Unit (returns no value or void) to each element.

    fileGroups.foreach {case (k, v) => printf("Number of files with extenson\t'%s'\t\t=%d\n", k, v.length)}
    
    scala>  fileGroups.foreach {case (k, v) => println(k)}
    
    backup
    bash_logout
    local
    pacnew
    lock
    conf
    cache
    key
    shutdown
    updated
    cfg
    deny
    bashrc
    types
    rc
    gen
    defs
    
    scala>  fileGroups.foreach {case (k, v) => println(k, v.length)}
    (,42)
    (backup,1)
    (bash_logout,1)
    (local,1)
    (pacnew,1)
    (lock,1)
    (conf,34)
    (cache,1)
    (key,1)
    (shutdown,1)
    (updated,1)
    (cfg,2)
    (deny,1)
    (bashrc,1)
    (types,1)
    (rc,2)
    (gen,1)
    (defs,1)
    
    scala>  fileGroups.mapValues(_.length).foreach(println)
    (,42)
    (backup,1)
    (bash_logout,1)
    (local,1)
    (pacnew,1)
    (lock,1)
    (conf,34)
    (cache,1)
    (key,1)
    (shutdown,1)
    (updated,1)
    (cfg,2)
    (deny,1)
    (bashrc,1)
    (types,1)
    (rc,2)
    (gen,1)
    (defs,1)
    
    scala>  fileGroups.foreach {case (k, v) => printf("Number of files with extenson\t'%s'\t\t=%d\n", k, v.length)}
    Number of files with extenson   ''      =42
    Number of files with extenson   'backup'        =1
    Number of files with extenson   'bash_logout'       =1
    Number of files with extenson   'local'     =1
    Number of files with extenson   'pacnew'        =1
    Number of files with extenson   'lock'      =1
    Number of files with extenson   'conf'      =34
    Number of files with extenson   'cache'     =1
    Number of files with extenson   'key'       =1
    Number of files with extenson   'shutdown'      =1
    Number of files with extenson   'updated'       =1
    Number of files with extenson   'cfg'       =2
    Number of files with extenson   'deny'      =1
    Number of files with extenson   'bashrc'        =1
    Number of files with extenson   'types'     =1
    Number of files with extenson   'rc'        =2
    Number of files with extenson   'gen'       =1
    Number of files with extenson   'defs'      =1
    

    Method: .isEmpty -> Test if Map is empty.

    scala> fileGroups.isEmpty
    res151: Boolean = false
    

    Method: .toList -> Convert a Map to a list of key and values.

    scala> val fileCounts = fileGroups.mapValues(_.length)
    
    fileCounts: scala.collection.immutable.Map[String,Int] = Map("" -> 42,
    backup -> 1, bash_logout -> 1, local -> 1, pacnew -> 1, lock -> 1,
    conf -> 34, cache -> 1, key -> 1, shutdown -> 1, updated -> 1, cfg ->
    2, deny -> 1, bashrc -> 1, types -> 1, rc -> 2, gen -> 1, defs -> 1)
    
    
    
    scala> fileGroups.toList
    
    scala> fileCounts.toList
    res140: List[(String, Int)] = List(("",42), (backup,1),
    (bash_logout,1), (local,1), (pacnew,1), (lock,1), (conf,34),
    (cache,1), (key,1), (shutdown,1), (updated,1), (cfg,2), (deny,1),
    (bashrc,1), (types,1), (rc,2), (gen,1), (defs,1))
    

    Method: .toArray -> Convert a Map to an array of key and values.

    scala> val fileCounts = fileGroups.mapValues(_.length)
    
    scala> fileCounts.toArray
    res141: Array[(String, Int)] = Array(("",42), (backup,1),
    (bash_logout,1), (local,1), (pacnew,1), (lock,1), (conf,34),
    (cache,1), (key,1), (shutdown,1), (updated,1), (cfg,2), (deny,1),
    (bashrc,1), (types,1), (rc,2), (gen,1), (defs,1))
    

    1.7.3 Mutable Collections

    1.7.3.1 Array
    scala> val arr = Array(1, 2, 3, 4, 5, 6)
    arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    // Type tab after the dot to show the Array methods
    scala> arr.
    ++              filterNot            maxBy               span            
    ++:             find                 min                 splitAt         
    +:              flatMap              minBy               startsWith      
    /:              flatten              mkString            stringPrefix    
    :+              fold                 nonEmpty            sum             
    :\              foldLeft             orElse              tail            
    addString       foldRight            padTo               tails           
    aggregate       forall               par                 take            
    andThen         foreach              partition           takeRight       
    apply           genericBuilder       patch               takeWhile       
    applyOrElse     groupBy              permutations        to              
    array           grouped              prefixLength        toArray         
    canEqual        hasDefiniteSize      product             toBuffer        
    clone           head                 reduce              toIndexedSeq    
    collect         headOption           reduceLeft          toIterable      
    collectFirst    indexOf              reduceLeftOption    toIterator      
    combinations    indexOfSlice         reduceOption        toList          
    companion       indexWhere           reduceRight         toMap           
    compose         indices              reduceRightOption   toSeq           
    contains        init                 repr                toSet           
    containsSlice   inits                reverse             toStream        
    copyToArray     intersect            reverseIterator     toTraversable   
    copyToBuffer    isDefinedAt          reverseMap          toVector        
    corresponds     isEmpty              runWith             transform       
    count           isTraversableAgain   sameElements        transpose       
    deep            iterator             scan                union           
    diff            last                 scanLeft            unzip           
    distinct        lastIndexOf          scanRight           unzip3          
    drop            lastIndexOfSlice     segmentLength       update          
    dropRight       lastIndexWhere       seq                 updated         
    dropWhile       lastOption           size                view            
    elemManifest    length               slice               withFilter      
    elemTag         lengthCompare        sliding             zip             
    endsWith        lift                 sortBy              zipAll          
    exists          map                  sortWith            zipWithIndex    
    filter          max                  sorted
    

    Get first and last elements.

    scala> val arr = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    arr: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr.head
    res10: Double = 3.4
    
    scala> arr.tail
    res11: Array[Double] = Array(2.5, -4.5, 4.0, 5.0, -6.31)
    

    Get array tail (remove first element)

    scala> val arr = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    arr: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr.tail
    res25: Array[Double] = Array(2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr
    res26: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    

    Get nth-element.

    scala> val arr = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    arr: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr(0)
    res12: Double = 3.4
    
    scala> arr(1)
    res13: Double = 2.5
    
    scala> arr(4)
    res14: Double = 5.0
    
    scala> arr(10)
    java.lang.ArrayIndexOutOfBoundsException: 10
      ... 32 elided
    

    Change nth-element.

    scala> val arr = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    arr: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr(3)
    res0: Double = 4.0
    
    scala> arr(3) = 100.0
    
    scala> arr
    res2: Array[Double] = Array(3.4, 2.5, -4.5, 100.0, 5.0, -6.31)
    
    scala> arr(0)
    res3: Double = 3.4
    
    scala> arr(0) = 5.0
    
    scala> arr
    res5: Array[Double] = Array(5.0, 2.5, -4.5, 100.0, 5.0, -6.31)
    
    scala> arr(0)
    res6: Double = 5.0
    

    Get minimum and maximum elements.

    scala> arr
    res18: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr.max
    res19: Double = 5.0
    
    scala> arr.min
    res20: Double = -6.31
    

    Get array length.

    scala> val arr = Array(1, 2, 3, 4, 5, 6)
    arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    scala> arr.length
    length   lengthCompare
    
    scala> arr.length
    res6: Int = 6
    

    Reverse array.

    scala> val arr = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    arr: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr.reverse
    res16: Array[Double] = Array(-6.31, 5.0, 4.0, -4.5, 2.5, 3.4)
    
    scala> arr
    res17: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    

    Convert Array to List.

    scala> val arr = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    arr: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr.toList
    res21: List[Double] = List(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr
    res22: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    

    Get array sum:

    scala> val arr = Array(1, 2, 3, 4, 5, 6)
    arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    scala> arr.sum
    res7: Int = 21
    

    Get array product:

    scala> val arr = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    arr: Array[Double] = Array(3.4, 2.5, -4.5, 4.0, 5.0, -6.31)
    
    scala> arr.product
    res9: Double = 4827.15
    

    Map - Apply a function to all array elements.

    scala> val arr = Array(3, 2, -4, 4, 5, -6)
    arr: Array[Int] = Array(3, 2, -4, 4, 5, -6)
    
    // Map with anonymous function
    //--------------------------------------------------
    scala> arr.map (x => x * 3)
    res30: Array[Int] = Array(9, 6, -12, 12, 15, -18)
    
    scala> arr map (x => x * 3)
    res35: Array[Int] = Array(9, 6, -12, 12, 15, -18)
    
    // Map a function 
    // 
    scala> def fn(x: Int) = x * 2 - 5
    fn: (x: Int)Int
    
    scala> arr.map(fn)
    res34: Array[Int] = Array(1, -1, -13, 3, 5, -17)
    
    scala> arr map fn
    res36: Array[Int] = Array(1, -1, -13, 3, 5, -17)
    
    
    // Convert integer to double 
    scala> 10
    res41: Int = 10
    
    scala> 10.toDouble
    res42: Double = 10.0
    
    // Map a function that applies a method.
    //--------------------------------------------------
    scala> arr map (_.toDouble)
    res43: Array[Double] = Array(3.0, 2.0, -4.0, 4.0, 5.0, -6.0)
    
    scala> arr map (_.toString)
    res54: Array[String] = Array(3, 2, -4, 4, 5, -6)
    
    scala> arr map (_.toHexString)
    res58: Array[String] = Array(3, 2, fffffffc, 4, 5, fffffffa)
    
    // Math syntax sugars 
    //-----------------------------------------------
    scala> arr map (_ + 10)
    res44: Array[Int] = Array(13, 12, 6, 14, 15, 4)
    
    scala> arr map (_ * 10)
    res45: Array[Int] = Array(30, 20, -40, 40, 50, -60)
    
    scala> arr map (_ * 10) map (5 + _)
    res49: Array[Int] = Array(35, 25, -35, 45, 55, -55)
    
    scala> arr map (_ * 10) sum
    res48: Int = 40
    
    scala> arr
    res51: Array[Int] = Array(3, 2, -4, 4, 5, -6)
    
    //  13 = 16 - 3
    //  14 = 16 - 2
    //  20 = 16 -(-4) 
    //  ... ... 
    scala> arr map (16 - _)
    res52: Array[Int] = Array(13, 14, 20, 12, 11, 22)
    

    Filter - an array. Select all array elements that satisfies a predicate.

    scala> val arr = Array(3, 2, -4, 4, 5, -6)
    arr: Array[Int] = Array(3, 2, -4, 4, 5, -6)
    
    scala> arr.filter(x => x > 0)
    res68: Array[Int] = Array(3, 2, 4, 5
    
    scala> arr filter (x => x > 0)
    res70: Array[Int] = Array(3, 2, 4, 5)
    
    scala> arr filter (x => x > 0) sum
    res71: Int = 14
    
    scala> arr filter (x => x > 0) product
    res72: Int = 120
    
    
    scala> arr.filter(_ > 0)
    res74: Array[Int] = Array(3, 2, 4, 5)
    
    scala> arr.filter(_ < 0)
    res77: Array[Int] = Array(-4, -6)
    
    scala> arr filter (_ < 0)
    res78: Array[Int] = Array(-4, -6)
    

    Reduce (fold). It fails for empty arrays.

    • acc stands for accumulator.
    scala> val arr = Array(1, 2, 3, 4, 5, 6)
    arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    // sum of array elements 
    scala> arr.reduce((acc, x) => acc + x)
    res12: Int = 21
    
    scala> arr.sum
    res15: Int = 21
    
    // product of array elements 
    scala> arr.reduce((acc, x) => acc * x)
    res16: Int = 720
    
    scala> arr.product
    res17: Int = 720
    
    scala> arr.reduce((acc, x) => 10 * acc + x)
    res18: Int = 123456
    
    scala> arr reduce((acc, x) => acc * x)
    res21: Int = 720
    
    
    scala> val emptyArr: Array[Double] = Array()
    emptyArr: Array[Double] = Array()
    
    scala> emptyArr.reduce((acc, x) => 10 * acc + x)
    java.lang.UnsupportedOperationException: empty.reduceLeft
      at scala.collection.TraversableOnce$class.reduceLeft(TraversableOnce.scala:180)
      at scala.collection.mutable.ArrayOps$ofDouble.scala$collection$IndexedSeqOptimized$$super$reduceLeft(ArrayOps.scala:270)
      at scala.collection.IndexedSeqOptimized$class.reduceLeft(IndexedSeqOptimized.scala:74)
      at scala.collection.mutable.ArrayOps$ofDouble.reduceLeft(ArrayOps.scala:270)
      at scala.collection.TraversableOnce$class.reduce(TraversableOnce.scala:208)
      at scala.collection.mutable.ArrayOps$ofDouble.reduce(ArrayOps.scala:270)
      ... 32 elided
    

    foldLeft - Like reduce, but it works for empty arrays.

    scala> val arr = Array(1, 2, 3, 4, 5, 6)
    arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    scala> val emptyArr : Array[Int] = Array()
    emptyArr: Array[Int] = Array()
    
    scala> arr.foldLeft(0)((acc, x) => 10 * acc + x)
    res30: Int = 123456
    
    scala> emptyArr.foldLeft(0)((acc, x) => 10 * acc + x)
    res33: Int = 0
    
    
    scala> arr.foldLeft(1)((acc, x) => acc * x)
    res38: Int = 720
    
    scala> emptyArr.foldLeft(1)((acc, x) => acc * x)
    res39: Int = 1
    
    scala> arr.foldLeft(())((_, x) => println(x))
    1
    2
    3
    4
    5
    6
    
    // - '()' - Unit type 
    //
    scala> emptyArr.foldLeft(())((_, x) => println(x))
    
    scala> ()
    
    scala>
    

    foldRight

    scala> val arr = Array(1, 2, 3, 4, 5, 6)
    arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
    
    scala> val emptyArr : Array[Int] = Array()
    emptyArr: Array[Int] = Array()
    
    scala> arr.foldRight(0)((x, acc) => 10* acc + x)
    res46: Int = 654321
    
    scala> emptyArr.foldRight(0)((x, acc) => 10* acc + x)
    res47: Int = 0
    
    
    scala> arr.foldRight(0)((x, acc) => acc + x)
    res49: Int = 21
    
    scala> arr.foldRight(1)((x, acc) => acc * x)
    res50: Int = 720
    

    Group By

    • groupBy[k](f: Element => key) : Map[key, Array[Element]]
    def getFileExtension(file: String) = {
      val i = file.lastIndexOf('.')
      if ( i > 0)
        file.substring(i+1)
      else
        ""
    }
    
    
    val flist = List(
      "/downloads/magazine.pdf"
     ,"afile.html"
     ,"file2.html"
     ,"file3.png"
     ,"config"
     ,"imageFun.png"
     ,"unix.pdf"
     ,"script10.scala"
     ,"bashrc"
      )
    
    
    scala> val flist = List(
         |   "/downloads/magazine.pdf"
         |  ,"afile.html"
         |  ,"file2.html"
         |  ,"file3.png"
         |  ,"config"
         |  ,"imageFun.png"
         |  ,"unix.pdf"
         |  ,"script10.scala"
         |  ,"bashrc"
         |   )
    flist: List[String] = List(/downloads/magazine.pdf, afile.html, file2.html, file3.png, config, imageFun.png, unix.pdf, script10.scala, bashrc)
    
    
    scala> flist map getFileExtension
    res63: List[String] = List(pdf, html, html, png, "", png, pdf, scala, "")
    
    
    scala> val fgroups = flist.groupBy(getFileExtension) fgroups:
    scala.collection.immutable.Map[String,List[String]] = Map("" ->
    List(config, bashrc), png -> List(file3.png, imageFun.png), pdf ->
    List(/downloads/magazine.pdf, unix.pdf), scala ->
    List(script10.scala), html -> List(afile.html, file2.html))
    
    // Get extensions
    //
    scala> fgroups.keys
    res74: Iterable[String] = Set("", png, pdf, scala, html)
    
    scala> fgroups.keys.foreach(println)
    
    png
    pdf
    scala
    html
    
    // Get all files without extension
    //
    scala> fgroups.get("")
    res75: Option[List[String]] = Some(List(config, bashrc))
    
    scala> fgroups.get("").get
    res79: List[String] = List(config, bashrc)
    
    scala> fgroups.get("tgz")
    res81: Option[List[String]] = None
    
    scala> fgroups.get("tgz").get
    java.util.NoSuchElementException: None.get
      at scala.None$.get(Option.scala:347)
      at scala.None$.get(Option.scala:345)
      ... 32 elided
    
    
    // Get all files with extension *.png
    scala> fgroups.get("png")
    res76: Option[List[String]] = Some(List(file3.png, imageFun.png))
    
    
    scala> var files = (new java.io.File("/etc/")).listFiles().filter(_.isFile)
    files: Array[java.io.File] = Array(/etc/motd, /etc/gemrc,
    /etc/ld.so.cache, /etc/environment, /etc/sensors3.conf, /etc/gshadow,
    /etc/cron.deny, /etc/shadow-, /etc/vdpau_wrapper.cfg,
    /etc/pacman.conf, /etc/cpufreq-bench.conf, /etc/makepkg.conf,
    /etc/ld.so.conf, /etc/fstab, /etc/host.conf, /etc/rpc,
    /etc/mime.types, /etc/locale.gen, /etc/passwd, /etc/healthd.conf,
    /etc/gnome-vfs-mime-magic, /etc/ts.conf, /etc/resolvconf.conf,
    /etc/passwd-, /etc/logrotate.conf, /etc/locale.conf,
    /etc/pacman-mirrors.conf.20170402.backup, /etc/login.defs,
    /etc/sudoers, /etc/request-key.conf, /etc/bash.bashrc,
    /etc/anacrontab, /etc/nscd.conf, /etc/os-release, /etc/adjtime,
    /etc/dnsmasq.conf, /etc/netconfig, /etc/mail.rc, /etc/inputrc,
    /etc/nsswitch.conf, /etc/ntp.conf, /etc/updatedb.conf,
    /etc/dhcpcd.conf, /e...  scala>
    
    
    scala> val fileGroups = files.map(_.getPath).groupBy(getFileExtension)
    fileGroups: scala.collection.immutable.Map[String,Array[String]] =
    Map("" -> Array(/etc/motd, /etc/gemrc, /etc/environment, /etc/gshadow,
    /etc/shadow-, /etc/fstab, /etc/rpc, /etc/passwd,
    /etc/gnome-vfs-mime-magic, /etc/passwd-, /etc/sudoers,
    /etc/anacrontab, /etc/os-release, /etc/adjtime, /etc/netconfig,
    /etc/inputrc, /etc/timezone, /etc/shadow, /etc/lsb-release,
    /etc/shells, /etc/papersize, /etc/drirc, /etc/hostname, /etc/exports,
    /etc/machine-id, /etc/group-, /etc/nanorc, /etc/hosts, /etc/group,
    /etc/mtab, /etc/securetty, /etc/services, /etc/protocols,
    /etc/gshadow-, /etc/localtime, /etc/issue, /etc/ethertypes,
    /etc/manjaro-release, /etc/yaourtrc, /etc/profile, /etc/printcap,
    /etc/crypttab), backup ->
    Array(/etc/pacman-mirrors.conf.20170402.backup), bash_logout ->
    Array(/etc/bash.bash...  scala>
    
    
    scala> val fileGroups = files map(_.getPath) groupBy getFileExtension
    fileGroups: scala.collection.immutable.Map[String,Array[String]] =
    Map("" -> Array(/etc/motd, /etc/gemrc, /etc/environment, /etc/gshadow,
    /etc/shadow-, /etc/fstab, /etc/rpc, /etc/passwd,
    /etc/gnome-vfs-mime-magic, /etc/passwd-, /etc/sudoers,
    /etc/anacrontab, /etc/os-release, /etc/adjtime, /etc/netconfig,
    /etc/inputrc, /etc/timezone, /etc/shadow, /etc/lsb-release,
    /etc/shells, /etc/papersize, /etc/drirc, /etc/hostname, /etc/exports,
    /etc/machine-id, /etc/group-, /etc/nanorc, /etc/hosts, /etc/group,
    /etc/mtab, /etc/securetty, /etc/services, /etc/protocols,
    /etc/gshadow-, /etc/localtime, /etc/issue, /etc/ethertypes,
    /etc/manjaro-release, /etc/yaourtrc, /etc/profile, /etc/printcap,
    /etc/crypttab), backup ->
    Array(/etc/pacman-mirrors.conf.20170402.backup), bash_logout ->
    Array(/etc/bash.bash...  scala>
    
    /// Show all file extensions 
    scala> fileGroups.keys.foreach(println)
    
    backup
    bash_logout
    local
    pacnew
    lock
    conf
    cache
    key
    shutdown
    updated
    cfg
    deny
    bashrc
    types
    rc
    gen
    defs
    
    scala> fileGroups.get("conf")
    res90: Option[Array[String]] = Some([Ljava.lang.String;@610b9cb3)
    
    scala> fileGroups.get("conf").get res91: Array[String] =
    Array(/etc/sensors3.conf, /etc/pacman.conf, /etc/cpufreq-bench.conf,
    /etc/makepkg.conf, /etc/ld.so.conf, /etc/host.conf, /etc/healthd.conf,
    /etc/ts.conf, /etc/resolvconf.conf, /etc/logrotate.conf,
    /etc/locale.conf, /etc/request-key.conf, /etc/nscd.conf,
    /etc/dnsmasq.conf, /etc/nsswitch.conf, /etc/ntp.conf,
    /etc/updatedb.conf, /etc/dhcpcd.conf, /etc/krb5.conf,
    /etc/openswap.conf, /etc/vconsole.conf, /etc/mkinitcpio.conf,
    /etc/man_db.conf, /etc/mke2fs.conf, /etc/fuse.conf, /etc/asound.conf,
    /etc/mdadm.conf, /etc/pamac.conf, /etc/nfs.conf, /etc/nfsmount.conf,
    /etc/resolv.conf, /etc/gai.conf, /etc/pacman-mirrors.conf,
    /etc/rsyncd.conf)
    
    scala> fileGroups.get("conf").get.take(10).foreach(println)
    /etc/sensors3.conf
    /etc/pacman.conf
    /etc/cpufreq-bench.conf
    /etc/makepkg.conf
    /etc/ld.so.conf
    /etc/host.conf
    /etc/healthd.conf
    /etc/ts.conf
    /etc/resolvconf.conf
    /etc/logrotate.conf
    
    scala> fileGroups.get("cfg").get.take(10).foreach(println)
    /etc/vdpau_wrapper.cfg
    /etc/rc_maps.cfg
    
    /// Show all files without extension 
    scala> fileGroups.get("").get.take(10).foreach(println)
    /etc/motd
    /etc/gemrc
    /etc/environment
    /etc/gshadow
    /etc/shadow-
    /etc/fstab
    /etc/rpc
    /etc/passwd
    /etc/gnome-vfs-mime-magic
    /etc/passwd-
    
    // Get the number of files of each extension 
    cala> val fileCounts = fileGroups.mapValues(n => n.length)
    fileCounts: scala.collection.immutable.Map[String,Int] = Map("" -> 42,
    backup -> 1, bash_logout -> 1, local -> 1, pacnew -> 1, lock -> 1,
    conf -> 34, cache -> 1, key -> 1, shutdown -> 1, updated -> 1, cfg ->
    2, deny -> 1, bashrc -> 1, types -> 1, rc -> 2, gen -> 1, defs -> 1)
    
    // Count the number of *.cfg 
    scala> fileCounts.get("cfg").get
    res102: Int = 2
    
    // Count the number of files without extension
    scala> fileCounts.get("")
    res99: Option[Int] = Some(42)
    
    scala> fileCounts.get("conf")
    res100: Option[Int] = Some(34)
    
    scala> fileCounts.get("conf").get
    res101: Int = 34
    
    // Show how many files are of each extension.
    //
    // - 2 files with *.cfg extension and 42 without extension.
    //   
    scala> fileCounts.foreach(println)
    (,42)
    (backup,1)
    (bash_logout,1)
    (local,1)
    (pacnew,1)
    (lock,1)
    (conf,34)
    (cache,1)
    (key,1)
    (shutdown,1)
    (updated,1)
    (cfg,2)
    (deny,1)
    (bashrc,1)
    (types,1)
    (rc,2)
    (gen,1)
    (defs,1)
    

    Foreach - Apply a function that performs side-effect to each element.

    scala> val arr = Array(3, 2, -4, 4, 5, -6)
    arr: Array[Int] = Array(3, 2, -4, 4, 5, -6)
    
    scala> arr.foreach(println)
    3
    2
    -4
    4
    5
    -6
    
    scala> arr foreach println
    3
    2
    -4
    4
    5
    -6
    
    scala> arr.foreach(x => println("x = " + x))
    x = 3
    x = 2
    x = -4
    x = 4
    x = 5
    x = -6
    
    scala> arr foreach (x => println("x = " + x))
    x = 3
    x = 2
    x = -4
    x = 4
    x = 5
    x = -6
    
    
    // More practical example:
    //
    
    scala> var files = (new java.io.File("/etc/")).listFiles()
    
    files: Array[java.io.File] = Array(/etc/systemd, /etc/motd,
    /etc/gemrc, /etc/adobe, /etc/ld.so.cache, /etc/environment,
    /etc/libreoffice, /etc/rc_keymaps, /etc/sensors3.conf, /etc/gshadow,
    /etc/acpi, /etc/pkcs11, /etc/modules-load.d, ... )
    
    // Get the number of files
    //--------------------------------
    scala> files.length
    res80: Int = 188
    
    scala> files.size
    res81: Int = 188
    
    scala> files.head
    res82: java.io.File = /etc/systemd
    
    scala> files.last
    res83: java.io.File = /etc/rsyncd.conf
    
    scala> val f = files.head
    f: java.io.File = /etc/systemd
    
    scala> f. // Type tab to show class tabs 
    canExecute      getAbsoluteFile    getTotalSpace    list              setWritable   
    canRead         getAbsolutePath    getUsableSpace   listFiles         toPath        
    canWrite        getCanonicalFile   hashCode         mkdir             toString      
    compareTo       getCanonicalPath   isAbsolute       mkdirs            toURI         
    createNewFile   getFreeSpace       isDirectory      renameTo          toURL         
    delete          getName            isFile           setExecutable                   
    deleteOnExit    getParent          isHidden         setLastModified                 
    equals          getParentFile      lastModified     setReadOnly                     
    exists          getPath            length           setReadable
    
    scala> files.head.getName
    res84: String = systemd
    
    scala> files.head.getPath
    res86: String = /etc/systemd
    
    scala> files.head.toURL
    res87: java.net.URL = file:/etc/systemd/
    
    scala> files.head.toURI
    res88: java.net.URI = file:/etc/systemd/
    
    scala> files.head.isFile
    res89: Boolean = false
    
    scala> files.head.isDirectory
    res90: Boolean = true
    
    // Filter all file objects that are directory and take 10 directories.
    scala> files.filter(_.isDirectory).take(10)
    res94: Array[java.io.File] = Array(/etc/systemd, /etc/adobe, /etc/libreoffice, /etc/rc_keymaps, /etc/acpi, /etc/pkcs11, /etc/modules-load.d, /etc/gufw, /etc/security, /etc/tmpfiles.d)
    
    
    // Get directories and print 15.
    //
    scala> files.filter(_.isDirectory).take(15).foreach(println)
    /etc/systemd
    /etc/adobe
    /etc/libreoffice
    /etc/rc_keymaps
    /etc/acpi
    /etc/pkcs11
    /etc/modules-load.d
    /etc/gufw
    /etc/security
    /etc/tmpfiles.d
    /etc/ppp
    /etc/iptables
    /etc/pulse
    /etc/xinetd.d
    /etc/ca-certificates
    
    // Filter 5 files   
    scala> files.filter(_.isFile).take(5)
    res96: Array[java.io.File] = Array(/etc/motd, /etc/gemrc, /etc/ld.so.cache, /etc/environment, /etc/sensors3.conf)
    
    scala> files.filter(_.isFile).take(15).foreach(println)
    /etc/motd
    /etc/gemrc
    /etc/ld.so.cache
    /etc/environment
    /etc/sensors3.conf
    /etc/gshadow
    /etc/cron.deny
    /etc/shadow-
    /etc/vdpau_wrapper.cfg
    /etc/pacman.conf
    /etc/cpufreq-bench.conf
    /etc/makepkg.conf
    /etc/ld.so.conf
    /etc/fstab
    /etc/host.conf
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    files
      .filter(_.isFile)
      .take(15)
      .foreach(println)
    
    // Exiting paste mode, now interpreting.
    
    /etc/motd
    /etc/gemrc
    /etc/ld.so.cache
    /etc/environment
    /etc/sensors3.conf
    /etc/gshadow
    /etc/cron.deny
    /etc/shadow-
    /etc/vdpau_wrapper.cfg
    /etc/pacman.conf
    /etc/cpufreq-bench.conf
    /etc/makepkg.conf
    /etc/ld.so.conf
    /etc/fstab
    /etc/host.conf
    
    
    scala> files filter (_.isFile) take 15 foreach println
    /etc/motd
    /etc/gemrc
    /etc/ld.so.cache
    /etc/environment
    /etc/sensors3.conf
    /etc/gshadow
    /etc/cron.deny
    /etc/shadow-
    /etc/vdpau_wrapper.cfg
    /etc/pacman.conf
    /etc/cpufreq-bench.conf
    /etc/makepkg.conf
    /etc/ld.so.conf
    /etc/fstab
    /etc/host.conf
    
    1.7.3.2 Mutable List
    scala> import collection.mutable.ListBuffer
    import collection.mutable.ListBuffer
    
    scala> val xs = ListBuffer[Double]()
    xs: scala.collection.mutable.ListBuffer[Double] = ListBuffer()
    
    scala> (1 to 10).foreach(i => xs.append(i.toDouble * 2.5 - 4.0))
    
    scala> xs
    res42: scala.collection.mutable.ListBuffer[Double] = ListBuffer(-1.5, 1.0, 3.5, 6.0, 8.5, 11.0, 13.5, 16.0, 18.5, 21.0)
    
    scala>
    
    1.7.3.3 Mutable Maps   collection map hash
    scala> import scala.collection.mutable.Map
    import scala.collection.mutable.Map
    
    scala> val hmap1 = Map[Int, String]()
    hmap1: scala.collection.mutable.Map[Int,String] = Map()
    
    scala> hmap1 += (1 -> "Netherlands")
    res49: hmap1.type = Map(1 -> Netherlands)
    
    scala> hmap1 += (2 -> "Mexico")
    res50: hmap1.type = Map(2 -> Mexico, 1 -> Netherlands)
    
    scala> hmap1 += (3 -> "Italy")
    res51: hmap1.type = Map(2 -> Mexico, 1 -> Netherlands, 3 -> Italy)
    
    scala> hmap1 += (10 -> "Japan")
    
    res52: hmap1.type = Map(2 -> Mexico, 10 -> Japan, 1 -> Netherlands, 3 -> Italy)
    
    scala>
    scala> hmap1
    res53: scala.collection.mutable.Map[Int,String] = Map(2 -> Mexico, 10 -> Japan, 1 -> Netherlands, 3 -> Italy)
    
    scala> hmap1(3)
    res54: String = Italy
    
    scala> hmap1(10)
    res55: String = Japan
    
    scala> hmap1(100)
    java.util.NoSuchElementException: key not found: 100
      at scala.collection.MapLike$class.default(MapLike.scala:228)
      at scala.collection.AbstractMap.default(Map.scala:59)
      at scala.collection.mutable.HashMap.apply(HashMap.scala:65)
      ... 32 elided
    
    scala>
    

    1.7.4 Seq Trait/Interface

    Seq is trait or interface for collections with iterable interface and defined order of elements such as Array, List, and Vector which implement Seq trait.

    Example 1: Generalizing functions that operates over Seq collections.

    The function printElements only works for Arrays of ints.

    @ def printElements(xs: Array[Int]) = xs foreach println 
    defined function printElements
    @  
    
    @ printElements(Array(1, 2, 3, 4, 5)) 
    1
    2
    3
    4
    5
    
    @ printElements(List(1, 2, 3, 4, 5)) 
    cmd3.sc:1: type mismatch;
     found   : List[Int]
     required: Array[Int]
    val res3 = printElements(List(1, 2, 3, 4, 5))
                                 ^
    Compilation Failed
    @  
    
    @ printElements(Vector(1, 2, 3, 4, 5)) 
    cmd3.sc:1: type mismatch;
     found   : scala.collection.immutable.Vector[Int]
     required: Array[Int]
    val res3 = printElements(Vector(1, 2, 3, 4, 5))
                                   ^
    Compilation Failed
    @
    

    This function can be refactored in order to work with all those collections by replacing Array with Seq.

    @ def printElements(xs: Seq[Int]) = xs foreach println  
    defined function printElements
    
    @ printElements(Array(1, 2, 3, 4, 5))  
    1
    2
    3
    4
    5
    
    @ printElements(List(1, 2, 3, 4, 5))  
    1
    2
    3
    4
    5
    
    @ printElements(Vector(1, 2, 3, 4, 5))  
    1
    2
    3
    4
    5
    

    Example 2: Some Seq operations.

    @ val seq1: Seq[Int] = Array(1, 2, 3, 4) 
    seq1: Seq[Int] = WrappedArray(1, 2, 3, 4)
    
    @ val seq2: Seq[Int] = Vector(1, 2, 3, 4) 
    seq2: Seq[Int] = Vector(1, 2, 3, 4)
    
    @ val seq3: Seq[Int] = List(1, 3, 4) 
    seq3: Seq[Int] = List(1, 3, 4)
    
    @ seq1.sum 
    res10: Int = 10
    @ seq2.sum 
    res11: Int = 10
    @ seq3.sum 
    res12: Int = 8
    
    
    @ List(seq1, seq2, seq3) map (_.sum) 
    res13: List[Int] = List(10, 10, 8)
    @  
    @ List(seq1, seq2, seq3) map (_.product) 
    res14: List[Int] = List(24, 24, 12)
    @  
    
    @ def sum(s: Seq[Int]) = s.sum  
    defined function sum
    @ 
    
    @ sum(seq1) 
    res16: Int = 10
    @ sum(seq2) 
    res17: Int = 10
    @ sum(seq3) 
    res18: Int = 8
    @  
    
    @ sum(seq4) 
    res20: Int = 0
    @  
    
    @ val seq4 = scala.collection.mutable.ListBuffer[Int]() 
    seq4: collection.mutable.ListBuffer[Int] = ListBuffer()
    @  
    
    @ seq4.sum 
    res21: Int = 0
    @ seq4.append(1) 
    
    @ seq4.append(2) 
    
    @ seq4.append(3) 
    
    @ seq4 
    res27: collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
    @  
    
    @ seq4.sum 
    res25: Int = 6
    @  
    @ sum(seq4) 
    res28: Int = 6
    @  
    
    @ def getSecond[A](xs: Seq[A]) = xs(1) 
    defined function getSecond
    @  
    getSecond
    @ getSecond(seq1) 
    res30: Int = 2
    @ getSecond(seq2) 
    res31: Int = 2
    @ getSecond(seq3) 
    res32: Int = 3
    @ getSecond(seq4) 
    res33: Int = 2
    @
    

    References:

    1.8 Case classes and pattern matching

    Scala case classes are similar to Haskell algebraic data types and supports pattern matching. It is useful to represent abstract syntax trees and build interpreters and pasers.

    Example 1:

    • Sealed class means that it is not possible to define any other sublclass of class Shape.
    sealed abstract class Shape
    case class Square   (side: Double)                    extends Shape
    case class Rectangle(height: Double, width: Double)   extends Shape
    case class Circle   (radius: Double)                  extends Shape
    case class Triangle (a: Double, b: Double, c: Double) extends Shape
    
    
    def computeArea(shape: Shape) = shape match {
      case Square(x)       => x * x
      case Rectangle(w, h) => w * h
      case Circle(r)       => Math.PI * r * r
      case _               => error("Error: Not implemented. See Heron's formula.")
    }
    
    
    def computePerimiter(shape: Shape) = shape match {
      case Square(x)         => 4 * x
      case Rectangle(w, h)   => 2 * (w + h)
      case Circle(r)         => 2 * Math.PI * r 
      case Triangle(a, b, c) => a + b + c 
    }
    
    def classify(shape: Shape) = shape match {
      case Square(_)       => "square"
      case Rectangle(_,_)  => "rectangle"
      case Circle(_)       => "circle"
      case Triangle(_,_,_) => "triangle"
    }
    
    
    scala> val s = Square(10.0)
    s: Square = Square(10.0)
    
    scala> val r = Rectangle(5.0, 10.0)
    r: Rectangle = Rectangle(5.0,10.0)
    
    scala> val c = Circle(3.0)
    c: Circle = Circle(3.0)
    
    scala> val t = Triangle(2.0, 4.0, 5.0)
    t: Triangle = Triangle(2.0,4.0,5.0)
    
    scala> 
    
    
    scala> computeArea(s)
    res27: Double = 100.0
    
    scala> computeArea(r)
    res28: Double = 50.0
    
    scala> computeArea(t)
    java.lang.RuntimeException: Error: Not implemented. See heron formula.
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at .computeArea(<console>:25)
      ... 32 elided
    
    scala> 
    
    
    scala> List(s, r, t)
    res30: List[Product with Serializable with Shape] = List(Square(10.0), Rectangle(5.0,10.0), Triangle(2.0,4.0,5.0))
    
    scala> List(s, r, t).foreach(println)
    Square(10.0)
    Rectangle(5.0,10.0)
    Triangle(2.0,4.0,5.0)
    
    scala> List(s, r, t).map(classify)
    res32: List[String] = List(square, rectangle, triangle)
    
    scala> List(s, r, t).map(computePerimiter)
    res33: List[Double] = List(40.0, 30.0, 11.0)
    

    Example 2: Abstract syntax tree.

    sealed abstract class Expr
    case class Val(x: Int)           extends Expr
    case class Add(r: Expr, s: Expr) extends Expr
    case class Sub(r: Expr, s: Expr) extends Expr
    case class Mul(r: Expr, s: Expr) extends Expr
    
    
    // It is possible to define multiple interpreters for this AST.
    
    // This interpreter evaluates the AST 
    def evalExpr(expr: Expr): Int = expr match {
      case Val(n)    => n
      case Add(r, s) => computeExpr(r) + computeExpr(s)
      case Sub(r, s) => computeExpr(r) - computeExpr(s)
      case Mul(r, s) => computeExpr(r) * computeExpr(s)
    }
    
    
    // This interpreter show the expresion 
    def showExpr(expr: Expr): String = expr match {
      case Val(n)    => n.toString
    
      case Add(Val(x), Val(y)) => x + " + " + y
      case Sub(Val(x), Val(y)) => x + " - " + y
      case Mul(Val(x), Val(y)) => x + " * " + y    
    
      case Add(Val(x), s) => x + " + (" + showExpr(s) + ")"
      case Sub(Val(x), s) => x + " - (" + showExpr(s) + ")"
      case Mul(Val(x), s) => x + " * (" + showExpr(s) + ")"    
    
      case Add(r, Val(y)) => "(" + showExpr(r) + ") + " + y
      case Sub(r, Val(y)) => "(" + showExpr(r) + ") - " + y
      case Mul(r, Val(y)) => "(" + showExpr(r) + ") * " + y    
    
      case Add(r, s) => "(" + showExpr(r) + ") + (" + showExpr(s) + ")"
      case Sub(r, s) => "(" + showExpr(r) + ") - (" + showExpr(s) + ")"
      case Mul(r, s) => "(" + showExpr(r) + ") * (" + showExpr(s) + ")"
    }
    
    // This interpreter shows the expresion and its value 
    def showEval(expr: Expr) = {
      println(showExpr(expr) + " = " + evalExpr(expr))
    }
    
    
    
    scala> val e1 = Val(10)
    e1: Val = Val(10)
    
    scala> val e2 = Add(Val(10), Val(5))
    e2: Add = Add(Val(10),Val(5))
    
    scala> val e3 = Mul(Val(3), e2)
    e3: Mul = Mul(Val(3),Add(Val(10),Val(5)))
    
    scala> val e4 = Sub(e3, e1)
    e4: Sub = Sub(Mul(Val(3),Add(Val(10),Val(5))),Val(10))
    
    
    scala> evalExpr(e1)
    res56: Int = 10
    
    scala> evalExpr(e2)
    res57: Int = 15
    
    scala> evalExpr(e3)
    res58: Int = 45
    
    scala> evalExpr(e4)
    res59: Int = 35
    
    
    scala> showExpr(e1)
    res60: String = 10
    
    scala> showExpr(e2)
    res61: String = 10 + 5
    
    scala> showExpr(e3)
    res62: String = 3 * (10 + 5)
    
    scala> showExpr(e4)
    res63: String = (3 * (10 + 5)) - 10
    
    scala> List(e1, e2, e3, e4).foreach(println)
    Val(10)
    Add(Val(10),Val(5))
    Mul(Val(3),Add(Val(10),Val(5)))
    Sub(Mul(Val(3),Add(Val(10),Val(5))),Val(10))
    
    
    scala> List(e1, e2, e3, e4).foreach(showEval)
    10 = 10
    10 + 5 = 15
    3 * (10 + 5) = 45
    (3 * (10 + 5)) - 10 = 35
    

    1.9 Pattern Matching

    1.9.1 Pattern matching numbers

    Example 1 - Show month name.

    def getMonthName(month: Int) = month match {
      case 1  => "January"
      case 2  => "February"
      case 3  => "March"
      case 4  => "April"
      case 5  => "May"
      case 6  => "June"
      case 7  => "July"
      case 8  => "August"
      case 9  => "September"
      case 10 => "October"
      case 11 => "November"
      case 12 => "December"
      case _  => error("Error: Invalid month")
    }
    
    
    scala> getMonthName(1)
    res75: String = January
    
    scala> getMonthName(9)
    res76: String = September
    
    scala> getMonthName(0)
    java.lang.RuntimeException: Error: Invalid month
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at .getMonthName(<console>:26)
      ... 32 elided
    
    
    def getMonthName2(month: Int) = month match {
      case 1  => Some("January")
      case 2  => Some("February")
      case 3  => Some("March")
      case 4  => Some("April")
      case 5  => Some("May")
      case 6  => Some("June")
      case 7  => Some("July")
      case 8  => Some("August")
      case 9  => Some("September")
      case 10 => Some("October")
      case 11 => Some("November")
      case 12 => Some("December")
      case _  => None 
    }
    
    
    scala> getMonthName2(1)
    res78: Option[String] = Some(January)
    
    scala> getMonthName2(12)
    res79: Option[String] = Some(December)
    
    scala> getMonthName2(0)
    res80: Option[String] = None
    
    scala> getMonthName2(-10)
    res81: Option[String] = None
    

    1.9.2 Pattern matching with strings.

    Example 2 - Pattern matching with strings.

    def showCurrencyName(cur: String) = cur match {
      case "USD" => "United States Dollar"
      case "CAD" => "Canadian Dollar"
      case "EUR" => "Euro"
      case "AUD" => "Australian Dollar"
      case "GBP" => "Great Britain Pound"
      case "JPY" => "Japanese Yen"
      case "CNY" => "Chinese Yuan / Reminbi"
      case "HKD" => "Hong Kong Dollar"
      case "BRL" => "Brazilian Real"
      case "MXN" => "Mexican Peso"
      case "CHF" => "Switzerland Franc"
      case "XBT" => "Bitcoin"
      case _     => error("Error: I don't the name of this currency. Please teach me it.")
    }
    
    
    scala> showCurrencyName("CNY")
    res102: String = Chinese Yuan / Reminbi
    
    scala> showCurrencyName("JPY")
    res103: String = Japanese Yen
    
    scala> showCurrencyName("HKD")
    res104: String = Hong Kong Dollar
    
    scala> showCurrencyName("JPYx")
    java.lang.RuntimeException: Error: I don't the name of this currency. Please teach me it.
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at .showCurrencyName(<console>:26)
      ... 32 elided
    
    
    scala> List("CNY", "HKD", "AUD", "BRL").map(showCurrencyName).foreach(println)
    Chinese Yuan / Reminbi
    Hong Kong Dollar
    Australian Dollar
    Brazilian Real
    
    scala> showCurrencyName("XBT")
    res109: String = Bitcoin
    

    1.9.3 Pattern with number and case-classes.

    Example 3 - Pattern with number and case-classes.

    abstract sealed class Month
    case object Jan extends Month
    case object Feb extends Month
    case object Mar extends Month
    case object Apr extends Month
    case object May extends Month
    case object Jun extends Month
    case object Jul extends Month
    case object Aug extends Month
    case object Sep extends Month
    case object Oct extends Month
    case object Nov extends Month
    case object Dec extends Month
    
    def getMonthName(month: Month) = month match {
      case Jan => "January"
      case Feb => "February"
      case Mar => "March"
      case Apr => "April"
      case May => "May"
      case Jun => "June"
      case Jul => "July"
      case Aug => "August"
      case Sep => "September"
      case Oct => "October"
      case Nov => "November"
      case Dec => "December"
    }
    
    
    def numberToMonth(n: Int) = n match {
      case 1  => Jan
      case 2  => Feb
      case 3  => Mar
      case 4  => Apr
      case 5  => May
      case 6  => Jun
      case 7  => Jul
      case 8  => Aug
      case 9  => Sep
      case 10 => Oct
      case 11 => Nov
      case 12 => Dec
      case _  => error("Error: Invalid month number.")
    }
    
    
    def numberToMonth2(n: Int) = n match {
      case 1  => Some(Jan)
      case 2  => Some(Feb)
      case 3  => Some(Mar)
      case 4  => Some(Apr)
      case 5  => Some(May)
      case 6  => Some(Jun)
      case 7  => Some(Jul)
      case 8  => Some(Aug)
      case 9  => Some(Sep)
      case 10 => Some(Oct)
      case 11 => Some(Nov)
      case 12 => Some(Dec)
      case _  => None
    }
    
    
    scala> getMonthName(Jan)
    res85: String = January
    
    scala> getMonthName(Feb)
    res86: String = February
    
    scala> getMonthName(Aug)
    res87: String = August
    
    scala> getMonthName(Dec)
    res88: String = December
    
    
    scala> numberToMonth(1)
    res93: Product with Serializable with Month = Jan
    
    scala> numberToMonth(9)
    res94: Product with Serializable with Month = Sep
    
    scala> numberToMonth(-1)
    java.lang.RuntimeException: Error: Invalid month number.
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at .numberToMonth(<console>:39)
      ... 32 elided
    
    
    scala> numberToMonth2(1)
    res97: Option[Product with Serializable with Month] = Some(Jan)
    
    scala> numberToMonth2(2)
    res98: Option[Product with Serializable with Month] = Some(Feb)
    
    scala> numberToMonth2(12)
    res99: Option[Product with Serializable with Month] = Some(Dec)
    
    scala> numberToMonth2(-1)
    res100: Option[Product with Serializable with Month] = None
    
    scala> numberToMonth2(0)
    res101: Option[Product with Serializable with Month] = None
    

    1.9.4 Pattern matching with conditional.

    Example 4 - Pattern matching with conditional.

    def classifyNumber(n: Int) = n match {
      case x if x < 0               => println("Negative number")
      case 0                        => println("zero")
      case x if x > 0 && x % 2 == 0 => println("Positive even number")
      case _                        => println("Positive odd number")
    }
    
    scala> classifyNumber(-2)
    Negative number
    
    scala> classifyNumber(-10)
    Negative number
    
    scala> classifyNumber(0)
    zero
    
    scala> classifyNumber(2)
    Positive even number
    
    scala> classifyNumber(21)
    Positive odd number
    
    scala> classifyNumber(210)
    Positive even number
    
    scala> classifyNumber(1213)
    Positive odd number
    

    1.9.5 Recursive functions

    Example 5 - Recursive functions.

    def factorial(n: Int): Int = n match {
      case a if a < 0 => error("Error: Invalid input.")
      case 0 | 1      => 1
      case k          => k * factorial(k - 1)
    }
    
    
    scala> factorial(4)
    res126: Int = 24
    
    scala> factorial(5)
    res127: Int = 120
    
    scala> factorial(-5)
    java.lang.RuntimeException: Error: Invalid input.
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at .factorial(<console>:14)
      ... 32 elided
    
    scala> factorial(0)
    res129: Int = 1
    
    scala> factorial(1)
    res130: Int = 1
    

    Example 6 - Recursive list functions.

    scala> 1::List()
    res118: List[Int] = List(1)
    
    scala> 2::1::List()
    res119: List[Int] = List(2, 1)
    
    scala> 4::2::1::List()
    res120: List[Int] = List(4, 2, 1)
    
    
    def sumList(list: List[Int]): Int = list match {
      case List() => 0
      case hd::tl => hd + sumList(tl)
    }
    
    scala> sumList(List(1, 2, 3, 4, 5))
    res121: Int = 15
    
    scala> 
    
    def foreach[A](fn: A => Unit)(list: List[A]): Unit = list match {
      case List() => ()  // Do nothing.
      case hd::tl => fn(hd) ; foreach(fn)(tl)
    }
    
    scala> def foreach[A](fn: A => Unit)(list: List[A]): Unit = list match {
         |   case List() => ()  // Do nothing.
         |   case hd::tl => fn(hd) ; foreach(fn)(tl)
         | }
    foreach: [A](fn: A => Unit)(list: List[A])Unit
    
    scala> foreach(println)(List(1, 2, 3, 4))
    1
    2
    3
    4
    
    
    scala> val printAll = foreach(println)(_)
    printAll: List[Any] => Unit = <function1>
    
    
    
    scala> printAll(List("Hello", "World", "Scala"))
    Hello
    World
    Scala
    
    scala> printAll(List(1, 2, 3, 4, 5))
    1
    2
    3
    4
    5
    

    1.9.6 Destructuring

    1.9.6.1 Destructuring tuples
    scala> val (a, b) = (10, 20)
    a: Int = 10
    b: Int = 20
    
    scala> a + b
    res0: Int = 30
    
    scala> val tpl = (10, "hello", 'x')
    tpl: (Int, String, Char) = (10,hello,x)
    
    scala> val (x, y, z) = tpl
    x: Int = 10
    y: String = hello
    z: Char = x
    
    scala> x
    res1: Int = 10
    
    scala> y
    res2: String = hello
    
    scala> z
    res3: Char = x
    
    1.9.6.2 Destructuring List, Arrays and other collections
    scala> val List(a, b, c) = List(1, 2, 3)
    a: Int = 1
    b: Int = 2
    c: Int = 3
    
    scala> val List(a, b, c) = List(1, 2, 3, 4, 5, 6)
    scala.MatchError: List(1, 2, 3, 4, 5, 6) (of class scala.collection.immutable.$colon$colon)
      ... 29 elided
    
    
    scala> val Array(x, y, z) = Array(1, 2, 3)
    x: Int = 1
    y: Int = 2
    z: Int = 3
    
    scala> x + y + z
    res7: Int = 6
    
    1.9.6.3 Destructuring case classes
    case class Product(
      id:       Int,
      name:     String,
      price:    BigDecimal,
      quantity: Int
    )
    
    val inventory = List(
      Product(100, "Sugar", 1.24, 100),
      Product(201, "Carton of Milk", 2.25, 200),
      Product(300, "Carton of fresh orange juice", 4.5, 300),
    )
    
    def showProduct(product: Product) = {
      val Product(id, name, price, qnt) = product
      println(s"""
    name     = ${name}
    id       = ${id}
    price    = ${price}
    quantity = ${qnt}
    """.trim() + "\n"
      )
    }
    
    // Alternative way without destructuring
    def showProduct2(product: Product) = {
      println(s"""
    name     = ${product.name}
    id       = ${product.id}
    price    = ${prodcut.price}
    quantity = ${product.quantity}
    """.trim() + "\n"
      )
    }
    
    def getInventoryValue(inventory: List[Product]) = {
      inventory.foldLeft(0: BigDecimal){ (acc, product) =>
        val Product(_, _, price, qnt) = product
        acc + price * qnt 
      }
    }
    

    Running:

    scala>  inventory foreach showProduct
    name     = Sugar
    id       = 100
    price    = 1.24
    quantity = 100
    
    name     = Carton of Milk
    id       = 201
    price    = 2.25
    quantity = 200
    
    name     = Carton of fresh orange juice
    id       = 300
    price    = 4.5
    quantity = 300
    
    
    scala> getInventoryValue(inventory)
    res11: BigDecimal = 1924.00
    

    1.10 Option type

    1.10.1 Overview

    Scala's Option type is similar to Haskell's Maybe and to OCaml's Option type which allows to deal with null values, avoid nested null checkings and also lots of null exceptions or null pointer exception.

    1.10.2 Basic operations

    scala> Some(100)
    res0: Some[Int] = Some(100)
    
    scala> None
    res1: None.type = None
    
    scala> Option(100)
    res2: Option[Int] = Some(100)
    
    scala> Option(null)
    res3: Option[Null] = None
    
    scala> Option("opt")
    res4: Option[String] = Some(opt)
    
    scala> Option(null) : Option[String]
    res5: Option[String] = None
    
    scala> None : Option[String]
    res6: Option[String] = None
    

    1.10.3 Pattern matching

    Pattern matching an Option value

    def testPatternMatching(opt: Option[String]) = opt match {
        case Some(x) => println("Received: " + x)
        case None    => println("Received: None")
    }
    
    scala> def testPatternMatching(opt: Option[String]) = opt match {
         |     case Some(x) => println("Received: " + x)
         |     case None    => println("Received: None")
         | }
    testPatternMatching: (opt: Option[String])Unit
    
    
    scala> testPatternMatching(Some("avoiding null exceptions"))
    Received: avoiding null exceptions
    
    scala> testPatternMatching(None)
    Received: None
    
    scala> testPatternMatching(Option("avoiding null exceptions"))
    Received: avoiding null exceptions
    
    scala> testPatternMatching(Option(null))
    Received: None
    

    Pattern matching an option tuple:

    def safeSum(optA: Option[Double], optB: Option[Double]) = (optA, optB) match {
      case (Some(a), Some(b)) => Some(a + b)
      case _                  => None 
    }
    
    scala> safeSum(Some(10), Some(20))
    res16: Option[Double] = Some(30.0)
    
    scala> safeSum(None, Some(20))
    res17: Option[Double] = None
    
    scala> safeSum(Some(10), None)
    res18: Option[Double] = None
    
    scala> safeSum(None, None)
    res19: Option[Double] = None
    

    1.10.4 Option type as a collection

    The Scala's option is similar to Scala's collections like List, Array and Map with lots of useful higher order methods that accepts functions as argument.

    Get - Get the value of wrapped by the option type, but throws an exception if it is None.

    scala> val x1 = Some("Hello")
    x1: Some[String] = Some(Hello)
    
    scala> val x2 = Option("World")
    x2: Option[String] = Some(World)
    
    scala> val x3 = None
    x3: None.type = None
    
    scala> val x4: Option[String] = Option(null)
    x4: Option[String] = None
    
    
    scala> x1.get
    res50: String = Hello
    
    scala> x2.get
    res51: String = World
    
    scala> x3.get
    java.util.NoSuchElementException: None.get
      at scala.None$.get(Option.scala:349)
      ... 29 elided
    
    scala> x4.get
    java.util.NoSuchElementException: None.get
      at scala.None$.get(Option.scala:349)
      at scala.None$.get(Option.scala:347)
      ... 29 elided
    
    scala>
    

    GetOrElse

    scala> None.getOrElse _
    res111: (=> Nothing) => Nothing
    
    scala> Some(20).getOrElse(4)
    res112: Int = 20
    
    scala> (None: Option[Int]).getOrElse(4)
    res113: Int = 4
    
    scala> Some("hello").getOrElse("world")
    res114: String = hello
    
    scala> Option(null).getOrElse("world")
    res115: String = world
    
    scala> None.getOrElse("world")
    res116: String = world
    

    Map: - Apply a function to the option value wrapped by the option type.

    scala> val o1 = Some(10)
    o1: Some[Int] = Some(10)
    
    // Test with Some value
    //
    scala> val o2: Option[Int] = None
    o2: Option[Int] = None
    
    scala> o1.map(x => x * 3)
    res24: Option[Int] = Some(30)
    
    scala> o1.map(x => x * 3).map(x => x + 10)
    res26: Option[Int] = Some(40)
    
    // Test with None values 
    //
    scala> o2 
    res27: Option[Int] = None
    
    scala> o2 map (x => x * 3)
    res28: Option[Int] = None
    
    scala> o2 map (x => x * 3) map (x => x + 10)
    res29: Option[Int] = None
    

    Flatmap - It is similar to Haskell bind operator (>>=). But in Scala it is method, not a function as in Haskell.

    scala> Option(10) map (x => if (x > 5) Some(10) else None)
    res32: Option[Option[Int]] = Some(Some(10))
    
    scala> Option(3) map (x => if (x > 5) Some(10) else None)
    res33: Option[Option[Int]] = Some(None)
    
    scala> (None: Option[Int]) map (x => if (x > 5) Some(10) else None)
    res35: Option[Option[Int]] = None
    
    
    scala> Some(10) flatMap (x => if (x > 5) Some(10) else None)
    res36: Option[Int] = Some(10)
    
    scala> Some(2) flatMap (x => if (x > 5) Some(10) else None)
    res37: Option[Int] = None
    
    scala> (None: Option[Int]) flatMap (x => if (x > 5) Some(10) else None)
    res38: Option[Int] = None
    

    Flatten

    scala> Some(Some(10)).flatten
    res143: Option[Int] = Some(10)
    
    scala> Some(None).flatten
    res144: Option[Nothing] = None
    
    scala> None.flatten
    res145: Option[Nothing] = None
    
    scala> (Some(None): Option[Option[Int]]).flatten 
    res146: Option[Int] = None
    
    scala> (None: Option[Option[Int]]).flatten 
    res147: Option[Int] = None
    

    Foreach - Apply a function that performs some action to the value wrapped by the option type.

    scala> Some("Scala Option") foreach {s => println("Message = " + s)}
    Message = Scala Option
    
    scala> None foreach {s => println("Message = " + s)}
    
    scala> Option("Scala Option") foreach {s => println("Message = " + s)}
    Message = Scala Option
    
    scala> Option(null) foreach {s => println("Message = " + s)}
    
    scala>
    

    Find

    scala> Some(100).find(a => a < 10)
    res122: Option[Int] = None
    
    scala> Some(4).find(a => a < 10)
    res123: Option[Int] = Some(4)
    
    scala> Some(4) find (a => a < 10)
    res126: Option[Int] = Some(4)
    
    scala> (None: Option[Int]).find(a => a < 10)
    res125: Option[Int] = None
    

    Filter

    scala> Some(3).filter (a => a > 10)
    res131: Option[Int] = None
    
    scala> Some(100).filter (a => a > 10)
    res132: Option[Int] = Some(100)
    
    scala> (None: Option[Int]).filter (a => a > 10)
    res133: Option[Int] = None
    
    scala> Some(3).filter (_ > 10)
    res137: Option[Int] = None
    
    scala> Some(100).filter (_ > 10)
    res138: Option[Int] = Some(100)
    
    scala> (None: Option[Int]).filter (_ > 10)
    res139: Option[Int] = None
    

    Conversions

    scala> Some("Scala").toArray
    res160: Array[String] = Array(Scala)
    
    scala> (None: Option[String]).toArray
    res161: Array[String] = Array()
    
    scala> Option("Scala").toArray
    res162: Array[String] = Array(Scala)
    
    scala> (Option(null): Option[String]).toArray
    res163: Array[String] = Array()
    
    scala> Option("Scala").toList
    res164: List[String] = List(Scala)
    
    scala> (None: Option[String]).toList
    res165: List[String] = List()
    
    scala> Some("Scala").toList
    res166: List[String] = List(Scala)
    
    scala>
    

    1.10.5 For-loop

    For-loop: Option's for-loop is similar to Array's or list for-loop.

    scala> for(s <- List(1, 2, 3, 4)) println("x = " + s)
    x = 1
    x = 2
    x = 3
    x = 4
    
    scala> for(s <- Some("scala")) println("Message = " + s)
    Message = scala
    
    scala> for(s <- None) println("Message = " + s)
    
    scala>
    

    1.10.6 For-comprehensions

    Scala's for comprehension are very similar to Haskell's do-notation for Monad.

    Example 1:

    Scala:

    def safeSum(sa: Option[Int], sb: Option[Int]) = {
      for {
        a <- sa
        b <- sb 
      } yield a + b
    }
    
    scala> safeSum(Some(10), Some(20))
    res170: Option[Int] = Some(30)
    
    scala> safeSum(Some(10), None)
    res171: Option[Int] = None
    
    scala> safeSum(None, None)
    res172: Option[Int] = None
    
    
    /// -- Expanding to for-notation  -------
    
    def safeSum2(sa: Option[Int], sb: Option[Int]) = {
      sa.flatMap { a =>
      sb.map     { b => a + b}
      }
    }
    
    @ safeSum2 _
    res22: (Option[Int], Option[Int]) => Option[Int]
    
    
    @ safeSum2(Some(10), Some(2))
    res23: Option[Int] = Some(12)
    
    @ safeSum2(Some(10), None)
    res24: Option[Int] = None
    
    @ safeSum2(None, None)
    res25: Option[Int] = None
    

    Haskell:

    :{
    safeSum :: Maybe Int -> Maybe Int -> Maybe Int
    safeSum sa sb = do
      a <- sa
      b <- sb
      return ( a + b)
    :}
    
    > safeSum (Just 10) (Just 20)
    Just 30
    it :: Maybe Int
    > safeSum (Just 10) Nothing
    Nothing
    it :: Maybe Int
    > safeSum Nothing Nothing
    Nothing
    it :: Maybe Int
    >
    

    Example 2:

    def both[A, B](oa: Option[A], ob: Option[B]) =
      for {
        a <- oa
        b <- ob
        c = (a, b)
      } yield c
    
    scala> both(Some(10), Some("hello"))
    res214: Option[(Int, String)] = Some((10,hello))
    
    scala> both(Some(10), None: Option[String])
    res215: Option[(Int, String)] = None
    
    
    def both2[A, B](oa: Option[A], ob: Option[B]) =
      for {
        a <- oa
        b <- ob
      } yield (a, b)
    
    scala> both2(Some(10), Some("hello"))
    res216: Option[(Int, String)] = Some((10,hello))
    
    scala> both2(None: Option[Int], Some("hello"))
    res217: Option[(Int, String)] = None
    
    scala> both2(None: Option[Int], None: Option[String])
    res218: Option[(Int, String)] = None
    

    1.10.7 Avoiding null checking and null pointer exceptions

    The function getClibpoardText gets a string from clibpoard. It is non-safe and error prone as it is full of null checking and returns a null value. If the developer forgets to check for null at the point of use, it may lead the unexpected null-pointer exceptions at runtime that cannot be spot at compile-time or spot by the type system.

    It may get worse if the return value of this function is passed to other functions that dont't check for null values.

    • Situation 1: getClibpoardText will null checking and with possibility of returning null value.
    import java.awt.Toolkit
    import java.awt.datatransfer.{Clipboard, DataFlavor, Transferable}
    
    def getClipboardText() = {
      val clip = Toolkit.getDefaultToolkit().getSystemClipboard()
      if (clip == null)
        null
      else {
        val data = clip.getContents(null)
        if (data != null  && data.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor()))
          data.getTransferData(DataFlavor.stringFlavor).asInstanceOf[String]
        else 
          null    
      }
    }
    
    /// User copies some text and run this function
    ///
    scala> val text1 = getClipboardText()
    text1: String =
    "A class that implements a mechanism to transfer data using cut/copy/paste operations.
    FlavorListeners may be registered on an instance of the Clipboard class to be notified about changes to the set of DataFlavors available on this clipboard (see addFlavorListener(java.awt.datatransfer.FlavorListener)).
    
    "
    
    scala> text1.length
    res188: Int = 305
    
    
    /// User copies some image and run this function
    ///
    scala> val text2 = getClipboardText()
    text2: String = null
    
    scala> text2.length
    java.lang.NullPointerException
      ... 29 elided
    
    scala> { val text3 = getClipboardText() ; if (text3 != null) text3.length else null }
    res190: Any = null
    
    def tellSize1(s: String) = println("String size is = " + s.length)
    
    /// User copies some text 
    scala> tellSize1(getClipboardText())
    String size is = 305
    
    /// User copies some image. The function getClibpoardtext returns null.
    scala> tellSize1(getClipboardText())
    java.lang.NullPointerException
      at .tellSize1(<console>:21)
      ... 29 elided
    
    
    def tellSize2(s: String) = {
      if (s != null)
         println("String size is = " + s.length)
    }
    
    scala> tellSize2(getClipboardText())
    String size is = 94
    
    scala> tellSize2(getClipboardText())
    

    By refactoring the aforementioned code to use option type instead of null values, it leads to a more concise and type-safe code where it is no longer necessary to check for null values and there is no more risk of unexpected null exceptions at run-time.

    • Situation 2: getClibpoardText with Option type.
    import java.awt.Toolkit
    import java.awt.datatransfer.{Clipboard, DataFlavor, Transferable}
    
    def getClipboardText() = for {
      clip <- Option(Toolkit.getDefaultToolkit().getSystemClipboard())
      data <- Option(clip.getContents(null))
      if data.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())
      text = data.getTransferData(DataFlavor.stringFlavor).asInstanceOf[String]
    } yield text
    
    
    scala> getClipboardText _
    res200: () => Option[String]
    
    //----------------------------
    //
    // User copies some text 
    scala> getClipboardText()
    res201: Option[String] = Some(JGoodies Binding: Property Adapter Example 3 : Data Binding « Swing Components « Java)
    
    // User copies an image
    scala> getClipboardText()
    res202: Option[String] = None
    
    //----------------------------
    //
    // User copies some text 
    scala> getClipboardText() foreach println
    def error(message: String) = throw new Exception(message)
    
    // User copies an image
    scala> getClipboardText() foreach println
    
    
    //----------------------------
    //
    // User copies some text 
    scala> getClipboardText() map (_.length)
    res207: Option[Int] = Some(23)
    
    scala> getClipboardText().map(_.length).get
    res211: Int = 68
    
    // User copies an image
    scala> getClipboardText() map (_.length)
    res208: Option[Int] = None
    
    scala> getClipboardText().map(_.length).get
    java.util.NoSuchElementException: None.get
      at scala.None$.get(Option.scala:349)
      at scala.None$.get(Option.scala:347)
      ... 29 elided
    
    
    scala> def tellSize1(s: String) = println("String size is = " + s.length)
    tellSize1: (s: String)Unit
    
    scala> getClipboardText() foreach tellSize1
    String size is = 101
    

    It can be refactored to more sef-contained code.

    def getClipboardText() = {
      import java.awt.Toolkit
      import java.awt.datatransfer.{Clipboard, DataFlavor, Transferable}
      for {
        clip <- Option(Toolkit.getDefaultToolkit().getSystemClipboard())
        data <- Option(clip.getContents(null))
        if data.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())
        text = data.getTransferData(DataFlavor.stringFlavor).asInstanceOf[String]
      } yield text
    }
    

    1.11 Exception Handling with try-catch

    1.11.1 Overview

    An exception is an event that happens during the execution of a programs which disrupts the normal flow of execution or an unexpected runtime error that terminates the execution abnormally. Handling them is necessary to create robust programs resilient that can react to failures, invalid input, network error and so on.

    Exception Hierarchy

    • Throwable
      • Error - System errors or fatal error thrown by JVM that ends the program execution and should not be handled by the application.
        • LinkageError
        • VirtualMachineError
        • AWTError
        • AssertionError
          • Cause: Assertion errors happens when the program assumptions are wrong, for instance, assert (10 == 0, "The result should be 10")
        • … … … …
      • Exception - Errors that can be handled by the program.
        • ClassNotFoundException
        • SQLException
        • IOException
          • FileNotFoundException
          • MalformedURLException
          • SocketException
          • EOFException
          • InterruptedIOException
        • RuntimeException
          • ArtithmeticException
            • Case: Division by zero.
          • NullPointerException
            • Cause: Calling a method or accessing a field of a class which the value is set to null.
          • IndexOutofBoundsException
            • Cause: Accessing out-of-bounds array elements.
          • IllegalArgumentException
            • Cause: Sending illegal argument to a method like sending a negative number to the method .runWithDelay(time: Int).
          • IllegalStateException
          • NumberFormatException
            • Cause: Attempt to convert a bad-formatted string to some value. Example: Integer.parseInt("xyz")
          • ClassCastException
            • Cause: Invalid casting.
          • … … … … …

    Exception Methods:

    • .getMessage() - Get exception Message.
    • .getStackTrace()
    • .getStackTraceString()
    • .printStackTrace()

    1.11.2 Throwing Exceptions

    scala> throw new IllegalArgumentException("Error: Amount to withdraw cannot excede balance")
    java.lang.IllegalArgumentException: Error: Amount to withdraw cannot excede balance
      ... 29 elided
    
    scala> throw new Exception("Error: Invalid user input. Fatal kernel failure.")
    java.lang.Exception: Error: Invalid user input. Fatal kernel failure.
      ... 29 elided
    
    scala> throw new java.lang.ArrayIndexOutOfBoundsException()
    java.lang.ArrayIndexOutOfBoundsException
      ... 29 elided
    
    scala> throw new NullPointerException()
    java.lang.NullPointerException
      ... 29 elided
    
    scala> throw new AssertionError("The result should be 10")
    java.lang.AssertionError: The result should be 10
      ... 29 elided
    
    scala> throw new Error("Fatal failure. Aborting exectution")
    java.lang.Error: Fatal failure. Aborting exectution
      ... 29 elided
    

    1.11.3 Catching exceptions without finally block.

    Example 1

    def testException1(block: => Unit) = { 
        try block 
        catch {  
          case ex: IllegalArgumentException         => println("Error: Illegal exception") 
          case ex: IllegalStateException            => println("Error: Illegal state exception") 
          case ex: java.io.FileNotFoundException    => println("Error: File not found exception ")
    
          case ex: Exception                        => println("Error: Unknown exception")
        } 
    } 
    
    
    scala> testException1{ println("It is not gonna fail.") }
    It is not gonna fail.
    
    scala> testException1{ new java.io.FileReader("/etc/somefile") }
    Error: File not found exception 
    
    scala> testException1{ assert(10 == 0) }
    java.lang.AssertionError: assertion failed
      at scala.Predef$.assert(Predef.scala:204)
      at .$anonfun$res41$1(<console>:13)
      at .testException1(<console>:12)
      ... 29 elided
    

    Example 2: Catching exceptions with try block.

    def showException(label: String, ex: Exception) = {
      println(label)
      println(ex)
      println(ex.printStackTrace())
    }
    
    def testException2(block: => Unit) = {
        try block 
        catch {  
    
          case ex: java.io.FileNotFoundException
              => showException("Error: File not found exception", ex)
    
          case ex: java.io.IOException
              => showException("Error: IO Exception", ex)
    
          case ex: NullPointerException
              => showException("Error: Null exception", ex)
    
          case ex: IllegalArgumentException
              => showException("Error: Illegal Argument exception.", ex)
    
          case ex: IllegalStateException
              => showException("Error: Illegal state exception", ex)
    
          case ex: Exception
              => showException("Error: Unknown exception", ex) 
    
        } finally {
          println("After 'finally' statement this piece of code always runs.")
        }
    } 
    
    scala> testException2{ println("This code will not throw an exception") }
    This code will not throw an exception
    After 'finally' statement this piece of code always runs.
    
    scala>  testException2{ println(10/ 0) }
    Error: Unknown exception
    java.lang.ArithmeticException: / by zero
    java.lang.ArithmeticException: / by zero
        at $line86.$read$$iw$$iw$.$anonfun$res30$1(<console>:13)
        at $line85.$read$$iw$$iw$.testException2(<pastie>:20)
        at $line86.$read$$iw$$iw$.<init>(<console>:13)
        at $line86.$read$$iw$$iw$.<clinit>(<console>)
        at $line86.$eval$.$print$lzycompute(<console>:7)
        at $line86.$eval$.$print(<console>:6)
    
    ... ...
    ()
    After 'finally' statement this piece of code always runs.
    
    
    scala> testException2{ val x: String = null ; println(x.length) }
    Error: Null exception
    java.lang.NullPointerException
    java.lang.NullPointerException
        at $line87.$read$$iw$$iw$.$anonfun$res31$1(<console>:14)
        at $line85.$read$$iw$$iw$.testException2(<pastie>:20)
          ... ... ... ...
    ()
    After 'finally' statement this piece of code always runs.
    
    
    scala> testException2{ new java.io.FileReader("/etc/fstabx") }
    Error: File not found exception
    java.io.FileNotFoundException: /etc/fstabx (No such file or directory)
    java.io.FileNotFoundException: /etc/fstabx (No such file or directory)
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(FileInputStream.java:195)
        at java.io.FileInputStream.<init>(FileInputStream.java:138)
          ... ... ... ...
    ()
    After 'finally' statement this piece of code always runs.
    
    
    // Exception not handled.
    //
    scala> testException2{ assert(10 == 5, "Result should be 10") }
    After 'finally' statement this piece of code always runs.
    java.lang.AssertionError: assertion failed: Result should be 10
      at scala.Predef$.assert(Predef.scala:219)
      at .$anonfun$res32$1(<console>:13)
      at .testException2(<pastie>:20)
      ... 29 elided
    

    Example 3: Catching exception and releasing resources.

    def displayFile(file: String) = {
      var fd: java.io.FileReader = null
      try {
        fd = new java.io.FileReader(file)
        val in = new java.util.Scanner(fd)
        while(in.hasNextLine()){
          println(in.nextLine())
        }
      } catch {
        case ex: java.io.FileNotFoundException => println("Error: File not found: ")
      } finally {
        if (fd != null) fd.close()
      }
    }
    
    scala> displayFile("/etc/lsb-release")
    DISTRIB_ID=ManjaroLinux
    DISTRIB_RELEASE=17.0.2
    DISTRIB_CODENAME=Gellivara
    DISTRIB_DESCRIPTION="Manjaro Linux"
    
    scala> displayFile("/etc/lsb-releaseq")
    Error: File not found:
    

    1.11.4 References

    1.12 Exception Handling with Try (scala.utils.Try)

    1.12.1 Overview

    Scala provides scala.util.Try which is similar to Option type and allows failures to be dealt in higher level way than try-catch blocks.

    The benefits of using Try type insted of using try-catch blocks are explicit faluire in the type system lots of useful combinators to handle failures such as map, flatMap, foreach and also for-comprehensions.

    The Try algebraic data type has two type constructors, Success which holds a result or successful computation and Failure which holds a failure or exception, which is a subtype of Trowable.

    sealed abstract class Try[+T]                extends AnyRef
    case class Success[+T](value: T)             extends Try[T]
    case class Failure[+T](exception: Throwable) extends Try[T]
    

    Documentation

    1.12.2 Examples

    1.12.2.1 Example 1: basic operations.
    import scala.util.{Try, Success, Failure}
    
    cala> val ma = Try{ 10 / 2}
    ma: scala.util.Try[Int] = Success(5)
    
    scala> val mb = Try{ 10 / 0}
    mb: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)
    
    //---- Map ------------
    
    scala> ma map { x => x + 10 }
    res2: scala.util.Try[Int] = Success(15)
    
    scala> mb map { x => x + 10 }
    res3: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)
    
    //----- Foreach --------
    
    
    scala> ma foreach {res => println("Result = " + res) }
    Result = 5
    
    scala> mb foreach {res => println("Result = " + res) }
    
    //------ Check if it is success ---------- //
    
    scala> ma.isSuccess
    res16: Boolean = true
    
    scala> mb.isSuccess
    res17: Boolean = false
    
    
    //------ Check if it is failure ---------- //
    
    scala> ma.isFailure
    res10: Boolean = false
    
    scala> mb.isFailure
    res11: Boolean = true
    
    
    //-------- Turn result into option type ------ //
    
    scala> ma.toOption
    res18: Option[Int] = Some(5)
    
    scala> mb.toOption
    res19: Option[Int] = None
    
    
    //------ Get the result or failure -----------//
    
    scala> ma.get
    res12: Int = 5
    
    scala> mb.get
    java.lang.ArithmeticException: / by zero
      at .$anonfun$mb$1(<console>:12)
      at scala.runtime.java8.JFunction0$mcI$sp.apply(JFunction0$mcI$sp.java:12)
      at scala.util.Try$.apply(Try.scala:209)
      ... 29 elided
    
    
    //----- Handling Result with pattern matching -------//
    
    ma match {
      case Success(a)
          => println("Successful result " + a)
      case Failure(e)
          => {
            println("Failure happend")
            println(e)
          }
    }
    
    
    scala> ma match {
         |   case Success(a)
         |       => println("Successful result " + a)
         |   case Failure(e)
         |       => {
         |         println("Failure happend")
         |         println(e)
         |       }
         | }
    Successful result 5
    
    
    mb match {
      case Success(a)
          => println("Successful result " + a)
      case Failure(e)
          => {
            println("Failure happend")
            println(e)
          }
    }
    
    scala> mb match {
         |   case Success(a)
         |       => println("Successful result " + a)
         |   case Failure(e)
         |       => {
         |         println("Failure happend")
         |         println(e)
         |       }
         | }
    Failure happend
    java.lang.ArithmeticException: / by zero
    
    1.12.2.2 Example 2: for-comprehensions.
    import scala.util.{Try, Success, Failure}
    
    def parseAndDivide1(strA: String, strB: String) = {
      for {
        a <- Try(strA.toInt)
        b <- Try(strB.toInt)
        c <- Try (a / b)
      } yield c 
    }
    
    scala> def parseAndDivide1(strA: String, strB: String) = {
         |   for {
         |     a <- Try(strA.toInt)
         |     b <- Try(strB.toInt)
         |     c <- Try (a / b)
         |   } yield c 
         | }
    parseAndDivide1: (strA: String, strB: String)scala.util.Try[Int]
    
    scala> parseAndDivide1("100", "20")
    res20: scala.util.Try[Int] = Success(5)
    
    scala> parseAndDivide1("100", "20x")
    res21: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "20x")
    
    scala> parseAndDivide1("10s0", "0")
    res22: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "10s0")
    
    scala> parseAndDivide1("100", "0")
    res23: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)
    
    
    
    scala> parseAndDivide1("100", "20") foreach { r => println("Result is equal to " + r)}
    Result is equal to 5
    
    scala> parseAndDivide1("100", "20a") foreach { r => println("Result is equal to " + r)}
    
    scala> parseAndDivide1("100", "0") foreach { r => println("Result is equal to " + r)}
    
    
    scala> parseAndDivide1("100", "20") map { x => x * 5 }
    res27: scala.util.Try[Int] = Success(25)
    
    scala> parseAndDivide1("100", "0") map { x => x * 5 }
    res28: scala.util.Try[Int] = Failure(java.lang.ArithmeticException: / by zero)
    
    scala> parseAndDivide1("4", "a") map { x => x * 5 }
    res30: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "a")
    
    1.12.2.3 Example 3: Pattern matching result.
    def parseAndDivide2(strA: String, strB: String) = {
      val res = for {
        a <- Try(strA.toInt)
        b <- Try(strB.toInt)
        c <- Try (a / b)
      } yield c
    
      res match {
        case Success(a) => {
          println("Successful result = " + a)
        }
        case Failure(e) => {
          println("Failure, try again! Game over!")
          println(e)
        }
      }
    }
    
    
    scala> parseAndDivide2("500", "10")
    Successful result = 50
    
    scala> parseAndDivide2("50d0", "10")
    Failure, try again! Game over!
    java.lang.NumberFormatException: For input string: "50d0"
    
    scala> parseAndDivide2("500", "0")
    Failure, try again! Game over!
    java.lang.ArithmeticException: / by zero
    
    1.12.2.4 Example 4: Pattern matching specific exceptions.
    def parseAndDivide3(strA: String, strB: String) = {
      val res = for {
        a <- Try(strA.toInt)
        b <- Try(strB.toInt)
        c <- Try (a / b)
      } yield c
    
      res match {
        case Success(a) => {
          println("Successful result = " + a)
        }
        case Failure(ex: java.lang.ArithmeticException) => {
          println("Failure was arithmetic exception")
        }
        case Failure(ex: java.lang.NumberFormatException) => {
          println("Failure was user bad input")
        }
        case Failure(e) => {
          println("I don't know how to deal with this kind of failure")
          println("Failure was \n" + e)
        }
      }
    }
    
    
    scala> parseAndDivide3("200", "50")
    Successful result = 4
    
    scala> parseAndDivide3("200a", "50")
    Failure was user bad input
    
    scala> parseAndDivide3("200", "50x")
    Failure was user bad input
    
    scala> parseAndDivide3("200", "0")
    Failure was arithmetic exception
    
    
    
    def parseAndDivide4(strA: String, strB: String) = {
      val res = for {
        a <- Try(strA.toInt)
        b <- Try(strB.toInt)
        c <- Try (a / b)
      } yield c
    
      res match {
        case Success(a) => {
          println("Successful result = " + a)
        }
        case Failure(e)
            => e match {
              case ex: java.lang.ArithmeticException
                  => {
                    println("Failure cause was arithmetic exception.")
                    println(e)
                    e.printStackTrace()
                  }
    
              case ex: java.lang.NumberFormatException
                  => {
                    println("Failure was user bad input.")
                    println(ex.getMessage())
                  }
    
              case e
                  => {
                    println("Error: I don't know how to deal with this failure")
                    println(e)
                  }
        }
      }
    }
    
    
    
    scala> parseAndDivide4("200", "20")
    Successful result = 10
    
    scala> parseAndDivide4("200a", "20")
    Failure was user bad input.
    For input string: "200a"
    
    scala> parseAndDivide4("200", "20x")
    Failure was user bad input.
    For input string: "20x"
    
    scala> parseAndDivide4("200", "0")
    Failure cause was arithmetic exception.
    java.lang.ArithmeticException: / by zero
    java.lang.ArithmeticException: / by zero
        at $line91.$read$$iw$$iw$$iw$$iw$.$anonfun$parseAndDivide4$5(<pastie>:20)
        at scala.runtime.java8.JFunction0$mcI$sp.apply(JFunction0$mcI$sp.java:12)
        at scala.util.Try$.apply(Try.scala:209)
        at $line91.$read$$iw$$iw$$iw$$iw$.$anonfun$parseAndDivide4$4(<pastie>:20)
        at $line91.$read$$iw$$iw$$iw$$iw$.$anonfun$parseAndDivide4$4$adapted(<pastie>:19)
        at scala.util.Success.flatMap(Try.scala:247)
    
     .... ... ... ... .... ... ... ...
    

    Possibilities:

    case e
        => {
          println("Error: I don't know how to deal with this failure")
    
          // Print exception
          println(e)
    
          // Print exception stack trace 
          e.printStackTrace()
    
          // Print exception message
          println(e.getMessage())
    
          // Throw exception again
          throw e 
        }
    
    1.12.2.5 Example 5: Try with http request
    import scala.util.{Try, Success, Failure}
    
    /** Read string from byte input source InputStream and its sub classes. 
    
       Note: This function doesn't close the input stream. It is supposed
       to be done by the caller.
    
       @param input - Byte input source 
       @param size  - Buffer size (default 1024 bytes or 1kb)
       @return        String.
      */
    def readInputToString(input: java.io.InputStream, size: Int = 1024): String = {
      val out = new java.io.ByteArrayOutputStream()
      // char[] buffer = new char[bufferSize]
      val buffer = new Array[Byte](size)
      // Number of bytes read 
      var rd = 0
      while( input.available() > 0){
        rd = input.read(buffer)
        out.write(buffer, 0, rd)
      }
      out.toString("UTF-8")
    }
    
    
    def httpGetRequest(url: String): Try[String] = {
      import java.net.{URL, HttpURLConnection}
      for {
        urlo <- Try{new URL(url)}
        conn <- Try{
          val c = urlo
            .openConnection()
            .asInstanceOf[java.net.HttpURLConnection]
    
          c.setRequestMethod("GET")
          c
        }
        is  <- Try{conn.getInputStream()}
        out <- Try{readInputToString(is)}
        _   <- Try{is.close()}
      } yield out 
    }
    
    
    def showResult[A](result: Try[A]): Unit = result match {
      case Success(x) => println(x)
      case Failure(e) => {
        println("Failure")
        println(e)
      }
    }
    
    scala> httpGetRequest("http://www.httpbin.org/get")
    res63: scala.util.Try[String] =
    Success({
      "args": {},
      "headers": {
        "Accept": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2",
        "Connection": "close",
        "Host": "www.httpbin.org",
        "User-Agent": "Java/1.8.0_144"
      },
      "origin": "176.18.51.232",
      "url": "http://www.httpbin.org/get"
    }
    )
    
    scala> httpGetRequest("https://www.httpbin.org/get")
    res66: scala.util.Try[String] =
    Success({
      "args": {},
      "headers": {
        "Accept": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2",
        "Connection": "close",
        "Host": "www.httpbin.org",
        "User-Agent": "Java/1.8.0_144"
      },
      "origin": "176.18.51.232",
      "url": "https://www.httpbin.org/get"
    }
    )
    
    scala> httpGetRequest("http://www.httpbin.org/getx")
    res64: scala.util.Try[String] = Failure(java.io.FileNotFoundException: http://www.httpbin.org/getx)
    
    scala> httpGetRequest("httpa://www.httpbin.org/get")
    res65: scala.util.Try[String] = Failure(java.net.MalformedURLException: unknown protocol: httpa)
    
    scala> httpGetRequest("http://www.fail.this.url")
    res67: scala.util.Try[String] = Failure(java.net.UnknownHostException: www.fail.this.url)
    
    // User disconnects in order to simulate a connection failure 
    //
    scala> httpGetRequest("http://www.httpbin.org/get")
    res69: scala.util.Try[String] = Failure(java.net.UnknownHostException: www.httpbin.org)
    
    
    scala>  showResult(httpGetRequest("httpx://www.httpbin.org"))
    Failure
    java.net.MalformedURLException: unknown protocol: httpx
    
    scala>  showResult(httpGetRequest("http://www.httpErrorbin.org"))
    Failure
    java.net.UnknownHostException: www.httpErrorbin.org
    
    scala>  showResult(httpGetRequest("http://www.httpbin.org/get"))
    {
      "args": {}, 
      "headers": {
        "Accept": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2", 
        "Connection": "close", 
        "Host": "www.httpbin.org", 
        "User-Agent": "Java/1.8.0_144"
      }, 
      "origin": "176.18.51.232", 
      "url": "http://www.httpbin.org/get"
    }
    

    1.13 For comprehensions and Monads

    1.13.1 Scala For-comprehensions and Haskell do-notation

    1.13.1.1 For-loop
    @ for (a <- 1 to 5) println(a) 
    1
    2
    3
    4
    5
    
    @ for (a <- List(1, 2, 3, 4, 5))  println(a)  
    1
    2
    3
    4
    5
    
    @ for {a <- List(1, 2, 3, 4, 5)}{ 
         println("a = " + a) 
      } 
    a = 1
    a = 2
    a = 3
    a = 4
    a = 5
    
    @ for (file <- new java.io.File("/").listFiles) println("file = " + file) 
    file = /lost+found
    file = /boot
    file = /run
    file = /usr
    file = /etc
    file = /sbin
    file = /tmp
    file = /mnt
    ... ... ... ...
    
    1.13.1.2 For-yield

    Scala's for-yield or for comprehension is similar to Haskell's monad do-notation. However unlike Haskell do-notation, which is dessugarized to (>>=) bind and return functions, Scala's for-yield notation is dessugarized to flatMap, map, filter and foreach method calls.

    Haskell Scala
       
    (>>=) or bind .flatMap
    return - Equivalent to object constructor. Option(10), Option(null), List(), List(1, 2, 3)
    fmap .map
    forM_ .foreach
    guard .filter or .withFilter
       
    • Note: .flatMap, .map, .foreach and .filter are methods.
    @ for (a <- 1 to 5) yield a 
    res30: collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5)
    
    @ for (a <- 1.to(5)) yield a  
    res44: collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5)
    
    @ for (a <- 1 to 5) yield (2 * a) 
    res31: collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
    
    @ for (file <- new java.io.File("/etc").listFiles) yield file.getName 
    res33: Array[String] = Array(
      "bash.bash_logout",
      "papersize",
      "exports.d",
      "apparmor.d",
      "shadow",
    ...
    
    
    @ for {
        file <- new java.io.File("/etc").listFiles
        val data = (file.getPath, file.getName, file.length)
    } yield data
    
    res47: Array[(String, String, Long)] = Array(
      ("/etc/bash.bash_logout", "bash.bash_logout", 28L),
      ("/etc/papersize", "papersize", 68L),
      ("/etc/exports.d", "exports.d", 4096L),
      ("/etc/apparmor.d", "apparmor.d", 4096L),
      ("/etc/shadow", "shadow", 1001L),
    ...
    
    
    //  
    //  Get the name of all directories in /etc/.
    @ for {
        file <- new java.io.File("/etc").listFiles
        if file.isDirectory // Rejects entries that aren't file.
      } yield file.getName() 
    
    res58: Array[String] = Array(
      "exports.d",
      "apparmor.d",
      "cron.weekly",
      "pulse",
      "iptables",
    ...
    
    
    @ val files = for {
        file <- new java.io.File("/etc").listFiles
        if file.isFile
    } yield file.getName()
    
    
    files: Array[String] = Array(
      "bash.bash_logout",
      "papersize",
      "shadow",
      "adjtime",
      "resolv.conf",
    ...
    
    @ files take 5 foreach println 
    bash.bash_logout
    papersize
    shadow
    adjtime
    resolv.conf
    

    Example 1

    Get all combinations between numbers 1, 2, 3, 4 and letters 'a' and 'b'.

    val c = for {
      a <- List(1, 2, 3, 4)
      b <- List('a', 'b')
    } yield (a, b)
    
    
    @ val c = for {
        a <- List(1, 2, 3, 4)
        b <- List('a', 'b')
    } yield (a, b)
    
    c: List[(Int, Char)] = List(
      (1, 'a'),
      (1, 'b'),
      (2, 'a'),
      (2, 'b'),
      (3, 'a'),
    ...
    
    @ c foreach println 
    (1,a)
    (1,b)
    (2,a)
    (2,b)
    (3,a)
    (3,b)
    (4,a)
    (4,b)
    

    Dessugarizing for-comprehension:

    val c = {
      List(1, 2, 3, 4).flatMap { a =>
      List('a', 'b').map       { b => (a, b) }}
    }
    
    @ val c = {
        List(1, 2, 3, 4).flatMap { a =>
        List('a', 'b').map       { b => (a, b) }}
      } 
    c: List[(Int, Char)] = List(
      (1, 'a'),
      (1, 'b'),
      (2, 'a'),
      (2, 'b'),
      (3, 'a'),
    ...
    
    @ c foreach println 
    (1,a)
    (1,b)
    (2,a)
    (2,b)
    (3,a)
    (3,b)
    (4,a)
    (4,b)
    

    Haskell Equivalent code:

    > import Control.Monad(forM_)
    
    :{
    xs = do
      a <- [1, 2, 3, 4]
      b <- ['a', 'b']
      return (a, b)     
    :}
    
    
    > :{
    - xs = do
    -   a <- [1, 2, 3, 4]
    -   b <- ['a', 'b']
    -   return (a, b)     
    - :}
    xs :: Num t => [(t, Char)]
    
    >  xs
    [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b'),(4,'a'),(4,'b')]
    it :: Num t => [(t, Char)]
    >
    
    
    > mapM_ print xs
    (1,'a')
    (1,'b')
    (2,'a')
    (2,'b')
    (3,'a')
    (3,'b')
    (4,'a')
    (4,'b')
    it :: ()
    > 
    
    > forM_ xs print
    (1,'a')
    (1,'b')
    (2,'a')
    (2,'b')
    (3,'a')
    (3,'b')
    (4,'a')
    (4,'b')
    it :: ()
    > 
    
    
    -- Do-notation dessugarized
    --
    :{
    xs2 = 
      [1, 2, 3, 4] >>= \ a ->
      ['a', 'b']   >>= \ b ->
      return (a, b)     
    :}
    
    > :{
    - xs2 = 
    -   [1, 2, 3, 4] >>= \ a ->
    -   ['a', 'b']   >>= \ b ->
    -   return (a, b)     
    - :}
    xs2 :: Num t => [(t, Char)]
    > 
    > xs2
    [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b'),(4,'a'),(4,'b')]
    it :: Num t => [(t, Char)]
    > 
    
    > mapM_ print xs2
    (1,'a')
    (1,'b')
    (2,'a')
    (2,'b')
    (3,'a')
    (3,'b')
    (4,'a')
    (4,'b')
    it :: ()
    >
    
    > forM_ xs2 print
    (1,'a')
    (1,'b')
    (2,'a')
    (2,'b')
    (3,'a')
    (3,'b')
    (4,'a')
    (4,'b')
    it :: ()
    >
    

    Example 2

    Get all pythagorean numbers from 1 to 100. Pythagorean numbers are integers that satisfies the equation c^2 = a^2 + b^2

    val pty = for { 
      a <- 1 to 100
      b <- 1 to 100
      c <- 1 to 100
      if (a * a + b * b == c * c)
    } yield (a, b, c)
    
    @ pty.take(10).foreach(println) 
    (3,4,5)
    (4,3,5)
    (5,12,13)
    (6,8,10)
    (7,24,25)
    (8,6,10)
    (8,15,17)
    (9,12,15)
    (9,40,41)
    (10,24,26)
    
    @ pty take 10 foreach println 
    (3,4,5)
    (4,3,5)
    (5,12,13)
    (6,8,10)
    (7,24,25)
    (8,6,10)
    (8,15,17)
    (9,12,15)
    (9,40,41)
    (10,24,26)
    

    Dessugarizing for-comprehension:

    val pty = (1 to 100).flatMap     { a =>
              (1 to 100).flatMap     { b =>
              (1 to 100).filter      { c => 
               a * a + b * b == c * c
              }.map{ c => (a, b, c)}
              }}
    
    pty: collection.immutable.IndexedSeq[(Int, Int, Int)] = Vector(
      (3, 4, 5),
      (4, 3, 5),
      (5, 12, 13),
      (6, 8, 10),
      (7, 24, 25),
    ...
    
    
    @ pty take 10 foreach println 
    (3,4,5)
    (4,3,5)
    (5,12,13)
    (6,8,10)
    (7,24,25)
    (8,6,10)
    (8,15,17)
    (9,12,15)
    (9,40,41)
    (10,24,26)
    

    Haskell equivalent code:

    > import Control.Monad (guard)
    >
    > :t guard
    guard :: GHC.Base.Alternative f => Bool -> f ()
    > 
    
    :{
    pty = do
      a <- [1 .. 100]
      b <- [1 .. 100]
      c <- [1 .. 100]
      guard (a * a + b * b == c * c)
      return (a, b, c)
    :}
    
     > :{
    - pty = do
    -   a <- [1 .. 100]
    -   b <- [1 .. 100]
    -   c <- [1 .. 100]
    -   guard (a * a + b * b == c * c)
    -   return (a, b, c)
    - :}
    pty :: (Eq t, Enum t, Num t) => [(t, t, t)]
    >
    
    > take 5 pty
    [(3,4,5),(4,3,5),(5,12,13),(6,8,10),(7,24,25)]
    it :: (Num t, Enum t, Eq t) => [(t, t, t)]
    > 
    
    > mapM_ print (take 10 pty)
    (3,4,5)
    (4,3,5)
    (5,12,13)
    (6,8,10)
    (7,24,25)
    (8,6,10)
    (8,15,17)
    (9,12,15)
    (9,40,41)
    (10,24,26)
    it :: ()
    > 
    
    :{
    pty2 = 
      [1 .. 100]                       >>= \ a ->
      [1 .. 100]                       >>= \ b ->
      [1 .. 100]                       >>= \ c ->
      guard (a * a + b * b == c * c)   >>= \ _ ->
      return (a, b, c)
    :}
    
    > take 5 pty2 
    [(3,4,5),(4,3,5),(5,12,13),(6,8,10),(7,24,25)]
    it :: (Num t, Enum t, Eq t) => [(t, t, t)]
    > 
    
    > mapM_ print (take 10 pty)
    (3,4,5)
    (4,3,5)
    (5,12,13)
    (6,8,10)
    (7,24,25)
    (8,6,10)
    (8,15,17)
    (9,12,15)
    (9,40,41)
    (10,24,26)
    it :: ()
    > 
    
    
    > :t (>>=)
    (>>=) :: Monad m => m a -> (a -> m b) -> m b
    >
    
    > let bind ma fn = ma >>= fn
    bind :: Monad m => m a -> (a -> m b) -> m b
    > 
    
    :{
    pty3 = 
      bind [1 .. 100]                        (\ a ->
      bind [1 .. 100]                        (\ b ->
      bind [1 .. 100]                        (\ c ->
      bind (guard (a * a + b * b == c * c))  (\ _ ->
      return (a, b, c)
                                             ))))
    :}
    
    > :{
    - pty3 = 
    -   bind [1 .. 100]                        (\ a ->
    -   bind [1 .. 100]                        (\ b ->
    -   bind [1 .. 100]                        (\ c ->
    -   bind (guard (a * a + b * b == c * c))  (\ _ ->
    -   return (a, b, c)
    -                                          ))))
    - :}
    pty3 :: (Eq t, Enum t, Num t) => [(t, t, t)]
    >
    
    > take 5 pty3 
    [(3,4,5),(4,3,5),(5,12,13),(6,8,10),(7,24,25)]
    it :: (Num t, Enum t, Eq t) => [(t, t, t)]
    > 
    
    :{
    pty4 = 
      [1 .. 100]                      `bind` \ a ->
      [1 .. 100]                      `bind` \ b ->
      [1 .. 100]                      `bind` \ c ->
      guard (a * a + b * b == c * c)  `bind` \ _ ->
      return (a, b, c)
    :}
    
    > :{
    - pty4 = 
    -   [1 .. 100]                      `bind` \ a ->
    -   [1 .. 100]                      `bind` \ b ->
    -   [1 .. 100]                      `bind` \ c ->
    -   guard (a * a + b * b == c * c)  `bind` \ _ ->
    -   return (a, b, c)
    - :}
    pty4 :: (Eq t, Enum t, Num t) => [(t, t, t)]
    > 
    
    > take 5 pty4 
    [(3,4,5),(4,3,5),(5,12,13),(6,8,10),(7,24,25)]
    it :: (Num t, Enum t, Eq t) => [(t, t, t)]
    >
    

    1.13.2 Options for comprehensions

    For - comprehension is equivalent to method .foreach

    scala> val ma : Option[Int] = Some(100)
    ma: Option[Int] = Some(100)
    
    scala> val mb : Option[Int] = None
    mb: Option[Int] = None
    
    scala> ma foreach println
    100
    
    scala> mb foreach println
    
    scala> for (x <- ma) println("x = " + x)
    x = 100
    
    scala> for (x <- mb) println("x = " + x)
    
    scala>
    
    
    
    scala> for {a <- Option(System.getProperty("java.home"))} println("Java Home = " + a)
    Java Home = /home/archbox/opt/jdk1.8.0_144/jre
    
    scala> for {a <- Option(System.getProperty("java.home error"))} println("Java Home = " + a)
    
    
    scala> Option(System.getProperty("java.home")) foreach { a => println("Java Home = " + a) }
    Java Home = /home/archbox/opt/jdk1.8.0_144/jre
    
    scala> Option(System.getProperty("java.home error")) foreach { a => println("Java Home = " + a) }
    

    For-yield equivalence to map

    scala> val ma : Option[Int] = Some(100)
    ma: Option[Int] = Some(100)
    
    scala> val mb : Option[Int] = None
    mb: Option[Int] = None
    
    
    scala> for (x <- ma) yield 5 * x
    res34: Option[Int] = Some(500)
    
    scala> for (x <- mb) yield 5 * x
    res35: Option[Int] = None
    
    
    scala> ma map (x => 5 * x)
    res36: Option[Int] = Some(500)
    
    scala> mb map (x => 5 * x)
    res37: Option[Int] = None
    

    For-yield expressions for Option type are a syntax sugar for nested flatMaps and maps method calls similar to Haskell's Maybe monad.

    def addSafe1(ma: Option[Int], mb: Option[Int]) = {
      for {
        a <- ma
        b <- mb
      } yield a + b
    }
    
    def addSafe2(ma: Option[Int], mb: Option[Int]) = {
      ma.flatMap { a =>
      mb.map     { b =>
        a + b
      }}
    }
    
    
    scala> addSafe1(Some(10), Some(15))
    res43: Option[Int] = Some(25)
    
    scala> addSafe1(Some(10), None)
    res44: Option[Int] = None
    
    scala> addSafe1(None, None)
    res45: Option[Int] = None
    
    
    scala> addSafe2(Some(10), Some(15))
    res46: Option[Int] = Some(25)
    
    scala> addSafe2(Some(10), None)
    res47: Option[Int] = None
    
    scala> addSafe2(None, None)
    res48: Option[Int] = None
    

    1.13.3 Identity Monad Implementation

    case class Identity[A](value: A) {
      def flatMap[B](fn: A => Identity[B]): Identity[B] = {
        fn(value)
      }
    
      def map[B](fn: A => B): Identity[B] = {
        Identity(fn(value))
      }
    
      def foreach[B](fn: A => Unit): Unit = fn(value)
    }
    
    
    @ Identity(10) 
    res65: Identity[Int] = Identity(10)
    
    @ Identity(10) map (x => x * 4) 
    res66: Identity[Int] = Identity(40)
    
    @ Identity(10) flatMap (x => Identity(x * 4)) 
    res67: Identity[Int] = Identity(40)
    
    
    @ for (x <- Identity(10)) println(x) 
    10
    
    @ for (x <- Identity("Hello world")) println(x) 
    Hello world
    
    @ for (x <- Identity(5)) yield 4 * x 
    res70: Identity[Int] = Identity(20)
    
    
    @ for {
        a <- Identity(10)
        b <- Identity(25)
      } yield a + b 
    res71: Identity[Int] = Identity(35)
    

    1.13.4 Maybe/Option implementation

    This example shows an Option type monad and collection implementation. It was named Maybe in order to avoid conflict with Scala's built in Option type.

    file: src/maybe-collection.scala

    // Sealed trait means that is not possible to add more
    // implementation of this trait/interface out of this file.
    // 
    sealed trait Maybe[+A]{
      def get(): A
    
      // Haskell's forM_ - Apply a function that returns nothing to a
      // collection. 
      //
      def foreach(a: A => Unit): Unit
    
      // Haskell's fmap
      //
      def map[B](fn: A => B): Maybe[B]
    
      // Haskell's (>>=) bind 
      // 
      def flatMap[B](fn: A => Maybe[B]): Maybe[B]
    
      // Haskell's guard 
      // 
      def withFilter(fn: A => Boolean): Maybe[A]
    
      def filter(fn: A => Boolean) = withFilter(fn)
    
    }
    
    
    // Equivalent to Haskell's Nothing or Scala's None.
    //
    //
    case object Empty extends Maybe[Nothing]{
      def get() = throw new RuntimeException("Error: Attemp to get data from Empty value")
    
      def foreach(fn: Nothing => Unit) = ()
    
      def map[B](fn: Nothing => B) = Empty
    
      def flatMap[B](fn: Nothing => Maybe[B]) = Empty
    
      def withFilter(fn: Nothing => Boolean) = Empty
    
    }
    
    // Similar to Haskell's Just or Scala's Some. 
    //
    //
    case class  Just[+A](value: A) extends Maybe[A]{
      def get() = value
    
      def foreach(fn: A => Unit) = fn(value)
    
      def map[B](fn: A => B) = Just(fn(value))
    
      def flatMap[B](fn: A => Maybe[B]) = fn(value)
    
      def withFilter(fn: A => Boolean): Maybe[A] = {
        if(fn(value))
          Just(value)
        else
          Empty
      }
    }
    
    // Companion object
    //
    object Maybe{
      def apply[A](value: A) = {
        if (value != null)
          Just(value)
        else
          Empty
      }
    
      def makeMaybeFn[A, B](fn: A => B) = (x: A) => {
        apply(fn(x))
      }
    
      def mapM2[A, B, C](fn: (A, B) => C, ma: Maybe[A], mb: Maybe[B]) = {
        for {
          a <- ma
          b <- mb 
        } yield fn(a, b)
      }
    
    }
    
    
    def addSafe(sa: Maybe[Int], sb: Maybe[Int]) = {
      for {
        a <- sa 
        b <- sb 
      } yield a + b 
    }
    
    def readNumber(prompt: String) = {
      try  {
        print(prompt)
        val sc = new java.util.Scanner(System.in)
        val n  = Just(sc.nextInt)
        print("\n")
        n
      } catch {
        case ex: java.util.InputMismatchException
            => Empty
      }
    }
    
    def parseInt(str: String): Maybe[Int] =  {
      try Just(str.toInt)
      catch {
        case ex: java.lang.NumberFormatException
            => Empty
      }
    }
    

    Test:

    scala> :paste src/maybe-collection.scala
    Pasting file src/maybe-collection.scala...
    defined trait Maybe
    defined object Empty
    defined class Just
    defined object Maybe
    addSafe: (sa: Maybe[Int], sb: Maybe[Int])Maybe[Int]
    readNumber: (prompt: String)Product with Serializable with Maybe[Int]
    parseInt: (str: String)Maybe[Int]
    
    
    //------- Test function apply ----------------
    //
    scala> Maybe(null) : Maybe[String] 
    res5: Maybe[String] = Empty
    
    scala> (Maybe(null) : Maybe[String]) foreach println
    
    scala> Maybe("Hello")  foreach println
    Hello
    
    scala> 
    
    
    //------ tet map, foreach, and get ------ // 
    
    scala> val ma: Maybe[Int] = Empty
    ma: Maybe[Int] = Empty
    
    scala> val mb: Maybe[Int] = Just(100)
    mb: Maybe[Int] = Just(100)
    
    
    scala> for (x <- ma) println("x = " + x)
    
    scala> for (x <- mb) println("x = " + x)
    x = 100
    
    
    scala> for (x <- ma) yield 5 * x
    res15: Maybe[Int] = Empty
    
    scala> for (x <- mb) yield 5 * x
    res16: Maybe[Int] = Just(500)
    
    
    scala> ma map (x => x * 5)
    res18: Maybe[Int] = Empty
    
    scala> mb map (x => x * 5)
    res19: Maybe[Int] = Just(500)
    
    //------- Test makeMaybeFn ---------- //
    
    // This static method, that can be regarded as function, returns null
    // which can unexpectedly crash the program. 
    //
    scala> System.getProperty("java.home")
    res21: String = /home/archbox/opt/jdk1.8.0_144/jre
    
    scala> System.getProperty("java.homex")
    res22: String = null
    
    scala> val getPropertySafe = Maybe.makeMaybeFn(System.getProperty)
    
    scala> getPropertySafe("java.homex")
    res23: Product with Serializable with Maybe[String] = Empty
    
    scala> getPropertySafe("java.home")
    res24: Product with Serializable with Maybe[String] = Just(/home/archbox/opt/jdk1.8.0_144/jre)
    
    scala> getPropertySafe("java.home") foreach println
    /home/archbox/opt/jdk1.8.0_144/jre
    
    scala> getPropertySafe("java.homex") foreach println
    
    
    //-------- Test function addSafe ---------
    
    scala> addSafe(parseInt("200"), parseInt("300"))
    res27: Maybe[Int] = Just(500)
    
    scala> addSafe(parseInt("200"), parseInt("300x"))
    res28: Maybe[Int] = Empty
    
    scala> addSafe(parseInt("20s0"), parseInt("300x"))
    res29: Maybe[Int] = Empty
    

    1.13.5 IO Monad Implementation

    File: src/iomonad.scala

    class IO[A](action: => A){
    
      import scala.util.{Try, Success, Failure}
    
      def run() = action
    
      def map[B](fn: A => B): IO[B] = {
        new IO(fn(action))
      }
    
      def flatMap[B](fn: A => IO[B]): IO[B] = {
        new IO(fn(action).run())
      }
    
      // Retry until successful 
      def retry() = {
        def aux(): A = {
          Try{action} match {
            case Success(a)
                => a
            case _
                => aux()          
          }
        }
        new IO(aux())
      }
    
    
      def forever() = {
        def aux(){
          this.run()
          aux()
        }
        new IO(aux())
      }
    
      def doTimes(n: Int) = {
        val io = this 
        new IO(for (i <- 1 to n) this.run())
      }
    
    } // ---- End of class IO ----- // 
    
    
    object IO{
      def apply[A](action: => A) = new IO(action)
    
      val readLine   = new IO(scala.io.StdIn.readLine())
      val readDouble = new IO(scala.io.StdIn.readDouble())
      val readInt    = new IO(scala.io.StdIn.readInt())
    
      def printn[A](a: A) = new IO(Predef.println(a))
      def print[A](a: A)  = new IO(Predef.print(a))
    
    
      def prompt(msg: String): IO[String] = for {
        _    <- print(msg)
        line <- readLine   
      } yield line 
    }
    
    
    def promptParse[A](msg: String, fn: String => A): IO[A] = 
      for {
        _    <- IO.print(msg)
        line <- IO.readLine
        _    <- IO.printn("")
      } yield fn(line)
    
    
    val getNumAndSum: IO[Int] =
      for {
        x <- promptParse("Enter x: ", _.toInt).retry
        y <- promptParse("Enter y: ", _.toInt).retry
      } yield x + y
    
    
    val main =
      for {
        _ <- IO.printn("\nTesting IO action getNumAndSum")
        x <- getNumAndSum
        _ <- IO.print("The result is = " + x)
      } yield ()
    
    
    // Uncomment the line below to run the program.
    main.forever().run()
    

    Running:

    $ scala -save  iomonad.scala 
    
    Testing IO action getNumAndSum
    Enter x: 200
    Enter y: sadsa
    Enter y: 300
    The result is = 500
    Testing IO action getNumAndSum
    Enter x: 500
    Enter y: 200
    The result is = 700
    Testing IO action getNumAndSum
    Enter x: sadsa
    Enter x: xhss
    Enter x: 
    Enter x:   
    Enter x: 89
    Enter y: 34
    The result is = 123
    Testing IO action getNumAndSum
    Enter x: 100
    Enter y: 200
    The result is = 300  # Enter Ctrl + C to end the program
    

    Experiment in the REPL:

    • This step requires the last line of the file to commented.
    scala> :paste iomonad.scala 
    Pasting file iomonad.scala...
    defined class IO
    defined object IO
    promptParse: [A](msg: String, fn: String => A)IO[A]
    getNumAndSum: IO[Int] = IO@388623ad
    main: IO[Unit] = IO@91f565d
    
    
    scala> IO.printn("Testing IO monad")
    res1: IO[Unit] = IO@3434a4f0
    
    scala> IO.printn("Testing IO monad") doTimes(5)
    res2: IO[Unit] = IO@53ea380b
    
    scala> IO.printn("Testing IO monad") doTimes(5) run()
    Testing IO monad
    Testing IO monad
    Testing IO monad
    Testing IO monad
    Testing IO monad
    
    
    scala> val action = promptParse("Enter a valid double: ", _.toDouble)
    action: IO[Double] = IO@2336cd91
    
    // User types 12345
    //-------------------
    scala> action.run()
    Enter a valid double: res10: Double = 12345.0
    
    // User types "error" 
    //-----------------
    scala> action.run()
    Enter a valid double: java.lang.NumberFormatException: For input string: "error"
      at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
      at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
      at java.lang.Double.parseDouble(Double.java:538)    
      ... ... ... ... 
    
    // Keep running IO action until user provides a valid input 
    //-----------------------
    scala> action.retry()
    res4: IO[Double] = IO@6bd28e4a
    
    scala> action.retry().run()
    Enter a valid double: 
    Enter a valid double: 
    Enter a valid double: 
    res5: Double = 12345.0
    
    // User types 100 
    //-----------------------------
    scala> action.retry() map (x => x * 4.0) run()
    Enter a valid double: 
    res7: Double = 400.0
    
    
    scala> action.map((x: Double) => x * 4.0).flatMap{ n => IO.printn("Result = " + n)}
    res12: IO[Unit] = IO@37e0614e
    
    scala> val action2 = action.map((x: Double) => x * 4.0).flatMap{ n => IO.printn("Result = " + n)}
    action2: IO[Unit] = IO@3e5d10fc
    
    // User types 45
    scala> action2.run()
    Enter a valid double: 
    Result = 180.0
    
    // User types 'error' in order to crash the program. 
    scala> action2.run()
    Enter a valid double: 
    java.lang.NumberFormatException: For input string: "error"
      at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
      at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
      at java.lang.Double.parseDouble(Double.java:538)
    
    // The IO action runs until user provides a valid input.
    //------------------------------
    scala> action2 retry() run()
    Enter a valid double: 
    Enter a valid double: 
    Enter a valid double: 
    Result = 60.0
    
    
    val action3 = for {
      x <- action
      n =  4.0 * x
      _ <- IO.printn("Result = " + n)
    } yield()
    
    
    scala> val action3 = for {
         |   x <- action
         |   n =  4.0 * x
         |   _ <- IO.printn("Result = " + n)
         | } yield()
    action3: IO[Unit] = IO@22b9f45f
    
    
    scala> action3.run()
    Enter a valid double: 
    Result = 48.0
    
    scala> action3.run()
    Enter a valid double: 
    java.lang.NumberFormatException: For input string: "crash"
      at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
      at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
      at java.lang.Double.parseDouble(Double.java:538)
    
    
    // Run IO action forever until user types Ctrl+C
    // ending the execution.
    //
    scala> action3 retry() forever() run()
    Enter a valid double: 
    Enter a valid double: 
    Enter a valid double: 
    Result = 496.0
    Enter a valid double: 
    Result = 140.0
    Enter a valid double: 
    Result = 48.0
    Enter a valid double: 
    Result = 20.0
    

    1.13.6 Reader Monad Implementation

    case class Reader[R, A](run: R => A){
    
      // Haskell fmap or <$> operator
      //
      def map[B](fn: A => B): Reader[R, B] = 
        Reader(r => fn(this.run(r)))
    
      // Haskell bind (>>=)
      //
      def flatMap[B](fn: A => Reader[R, B]): Reader[R, B] =
        Reader(r => fn(this.run(r)).run(r))
    
      def withReader[Z](fn: Z => R): Reader[Z, A] =
        Reader(z => this.run(fn(z)))
    
      def local(fn: R => R): Reader[R, A] =
        Reader(r => this.run(fn(r)))
    
      def foreach(fn: A => Unit): Reader[R, Unit] =
        Reader(r => fn(this.run(r)))
    
      // Haskell - runReader 
      def apply(x: R): A = run(x)  
    }
    
    object Reader{
    
      // Equivalent of Haskell return :: a -> (Reader r) a
      def pure[R, A](x: A) = Reader((_: R) => x)
    
      def ask[R] = Reader[R, R]((r: R) => r)
    }
    

    Testing:

    
    

    1.13.7 References

    1.14 OOP - Object Oriented Programming

    1.14.1 Everything is an object

    In Scala everything is an object:

    • Tuples are objects.
    scala> val t1 = (10, "20.2")
    t1: (Int, String) = (10,20.2)
    
    scala> t1._1
    res47: Int = 10
    
    scala> t1._2
    res48: String = 20.2
    
    
    scala> val t2 = new Tuple2(10, "20.2")
    t2: (Int, String) = (10,20.2)
    
    scala> t2._1
    res49: Int = 10
    
    scala> t2._2
    res50: String = 20.2
    
    scala> t1 == t2
    res51: Boolean = true
    
    
    scala> val t3 = new Tuple3(10, "aa", 20.4)
    t3: (Int, String, Double) = (10,aa,20.4)
    
    scala> t3._1
    res59: Int = 10
    
    scala> t3._2
    res60: String = aa
    
    scala> t3._3
    res61: Double = 20.4
    
    • Functions are objects
    val f1 = new Function1[Int, String]{
      def apply(x: Int) = (2 * x + 10).toString
    }
    
    scala> val f1 = new Function1[Int, String]{
         |   def apply(x: Int) = (2 * x + 10).toString
         | }
    f1: Int => String = <function1>
    
    scala> f1(10)
    res52: String = 30
    
    scala> f1(6)
    res53: String = 22
    
    
    val f2 = new Function2[Double, Double, Double]{
      def apply(x: Double,  y: Double) = 2 * x + y
    }
    
    scala> val f2 = new Function2[Double, Double, Double]{
         |   def apply(x: Double,  y: Double) = 2 * x + y
         | }
    f2: (Double, Double) => Double = <function2>
    
    scala> f2(2.0, 5.0)
    res54: Double = 9.0
    
    scala> f2(5.0, 2.0)
    res55: Double = 12.0
    
    • Numbers are objects and operators (+), (-), (/) are not operators, they are methods.
    scala> 10 + 5
    res56: Int = 15
    
    scala> 10.+(5)
    res57: Int = 15
    
    scala> List(1, 2, 3, 4).map(a => 10.+(a))
    res58: List[Int] = List(11, 12, 13, 14)
    

    1.14.2 Case classes as records

    Example: Simple record type.

    scala> case class Person(id: Int, firstName: String, lastName: String)
    defined class Person
    
    scala> val p1 = Person(100, "John", "Smith")
    p1: Person = Person(100,John,Smith)
    
     scala> val p2 = Person(600, "Isaac", "Newton")
    p3: Person = Person(600,Isaac,Newton)
    
    scala> p1.lastName
    res150: String = Smith
    
    scala> p1.lastName = ""
    <console>:16: error: reassignment to val
           p1.lastName = ""
                       ^
    
    scala> List(p1, p2).foreach(println)
    Person(100,John,Smith)
    Person(600,Isaac,Newton)
    
    scala> List(p1, p2).map(_.firstName)
    res167: List[String] = List(John, Isaac)
    
    scala> List(p1, p2).map(_.lastName)
    res168: List[String] = List(Smith, Newton)
    
    scala>
    

    1.14.3 Special Methods - Apply and Update

    1.14.3.1 Apply method - Callable objects

    The Scala Apply-method is used to create callable objects similar to C++'s "functor" (aka function-object) or an object that behaves like function.

    Example 1 - The apply method can be overloaded as a long as each version has a unique type signature.

    class ApplyTest{
      def apply(x: Int) =
        println("Apply called with integer - x = " + x)
    
      def apply(s: String) =
        println(s"Apply called with string - s = '$s' ")
    
      def apply(x: Double, y: Double) =
        println("x + y = " + (x + y))
    }
    
    scala> obj1(10)
    Apply called with integer - x = 10
    
    scala> obj1.apply(10)
    Apply called with integer - x = 10
    
    scala> obj1("hello world Scala, C++ functor function object")
    Apply called with string - s = 'hello world Scala, C++ functor function object'
    
    scala> obj1 apply "hello world Scala, C++ functor function object"
    Apply called with string - s = 'hello world Scala, C++ functor function object'
    
    scala> obj1(5.6, 2.435)
    x + y = 8.035
    
    scala> obj1 apply (5.6, 2.435)
    x + y = 8.035
    
    scala> obj1.apply(5.6, 2.435)
    x + y = 8.035
    

    Example 2 - Singleton objects can also have apply method and be called like functions.

    object SingletonModule {
      def apply(x: Int) =
        println("Apply called with integer - x = " + x)
    
      def apply(s: String) =
        println(s"Apply called with string - s = '$s' ")
    
      def apply(x: Double, y: Double) =
        println("x + y = " + (x + y))
    }
    
    scala> SingletonModule.apply(5)
    Apply called with integer - x = 5
    
    scala> SingletonModule.apply("C++'s function object")
    Apply called with string - s = 'C++'s function object'
    
    scala> SingletonModule("C++'s function object")
    Apply called with string - s = 'C++'s function object'
    
    scala> SingletonModule(3.5, 9.343)
    x + y = 12.843
    
    scala> SingletonModule.apply(3.5, 9.343)
    x + y = 12.843
    
    scala> SingletonModule apply (3.5, 9.343)
    x + y = 12.843
    

    Example 3

    class LinearEquation(a: Double = 0, b: Double = 0){
      private var (_a, _b) = (a, b)
    
      override def toString() =
        f"Linear equation = ${_a}%.3f * x + ${_b}%.3f "
    
      def setA(a: Double) =
        _a = a
    
      def setB(b: Double) =
        _b = b 
    
      // Compute the equation Y(x) = A * x + B at point x
      def compute(x: Double) =
        _a * x + _b
    
      def apply(x: Double) =
        _a * x + _b
    }
    

    The object lineq can be called as it was a function which is a syntax sugar for the apply method.

    // Equation 3 * x + 4
    scala> val lineq = new LinearEquation(3, 4)
    lineq: LinearEquation = Linear equation = 3.000 * x + 4.000
    
    // 3 * 0 + 4 = 0
    // --> It is a syntax sugar for the method apply.
    //-------------------------------------------
    scala> lineq(0)
    res40: Double = 4.0
    
    scala> lineq.apply(0)
    res50: Double = 4.0
    
    scala> lineq.compute(0.0)
    res47: Double = 4.0
    
    // 3 * 1 + 4 = 7
    //-------------------------------------------
    scala> lineq(1)
    res41: Double = 7.0
    
    scala> lineq.apply(1.0)
    res51: Double = 7.0
    
    scala> lineq.compute(1)
    res48: Double = 7.0
    
    // 3 * 2 + 4 = 6
    //-------------------------------------------
    scala> lineq(2)
    res42: Double = 10.0
    
    scala> lineq.apply(2)
    res52: Double = 10.0
    
    scala> lineq.compute(2)
    res49: Double = 10.0
    
    
    scala> List(1.0, 2.0, 3.0, 4.0) map lineq
    <console>:13: error: type mismatch;
     found   : LinearEquation
     required: Double => ?
           List(1.0, 2.0, 3.0, 4.0) map lineq
    
    scala> List(1.0, 2.0, 3.0, 4.0) map {lineq (_)}
    res64: List[Double] = List(7.0, 10.0, 13.0, 16.0)
    
    scala> List(1.0, 2.0, 3.0, 4.0) map lineq.compute
    res65: List[Double] = List(7.0, 10.0, 13.0, 16.0)
    
    // Change the coefficients to Y(x) = 5 * x + 0
    scala> lineq.setA(5)
    scala> lineq.setB(0)
    scala> List(1.0, 2.0, 3.0, 4.0) map {lineq(_)}
    res68: List[Double] = List(5.0, 10.0, 15.0, 20.0)
    
    1.14.3.2 Callable object comparison with closures

    A closure function could be used instead of a callable object providing the same results. The difference is that the objects can update their internal state at run-time while a closures cannot.

    def makeLinearEq(a: Double, b: Double) =
      (x: Double) => a * x + b
    
    scala> def makeLinearEq(a: Double, b: Double) =
         |   (x: Double) => a * x + b
    makeLinearEq: (a: Double, b: Double)Double => Double
    
    // Equation: Y(x) = 3 * x + 4 generated with closure 
    scala> val lineqClosure = makeLinearEq(3.0, 4.0)
    lineqClosure: Double => Double = $$Lambda$1577/1928574577@1ccc5740
    
    
    scala> lineqClosure(1.0)
    res70: Double = 7.0
    
    scala> lineqClosure(2.0)
    res72: Double = 10.0
    
    scala> List(1.0, 2.0, 3.0, 4.0) map lineqClosure
    res71: List[Double] = List(7.0, 10.0, 13.0, 16.0)
    
    // There is no way to update a and b to a = 5 and b = 0
    // keeping the original lambda function. The only way to accomplish this
    // is to generate a new function.
    scala> val lineqClosure2 = makeLinearEq(5.0, 0.0)
    lineqClosure2: Double => Double = $$Lambda$1577/1928574577@36715f68
    
    scala>  List(1.0, 2.0, 3.0, 4.0) map lineqClosure2
    res73: List[Double] = List(5.0, 10.0, 15.0, 20.0)
    
    
    scala> val lineq = new LinearEquation(3, 4)
    lineq: LinearEquation = Linear equation = 3.000 * x + 4.000
    
    scala>  List(1.0, 2.0, 3.0, 4.0) map { lineq (_) }
    res74: List[Double] = List(7.0, 10.0, 13.0, 16.0)
    
    // A Callable object can update its internal state at run-time.
    //
    scala> lineq.setA(5)
    scala> lineq.setB(0)
    scala> lineq
    res79: LinearEquation = Linear equation = 5.000 * x + 0.000
    
    scala>  List(1.0, 2.0, 3.0, 4.0) map { lineq (_) }
    res80: List[Double] = List(5.0, 10.0, 15.0, 20.0)
    
    scala>  List(1.0, 2.0, 3.0, 4.0) map lineq.compute
    res82: List[Double] = List(5.0, 10.0, 15.0, 20.0)
    

    Despite the closure limitations, the callable-object approach could be emulated with closures by returning multiple functions from the top-level function.

    // Case class is used here to emulate a record type 
    case class LinearEquationFn(
      setA: Double => Unit,
      getA: () => Double,  
      setB: Double => Unit,
      getB: () => Double,
      compute: Double => Double  
    ) {
      override def toString() =  {
        val (_a, _b) = (getA(), getB())
         f"Linear equation = ${_a}%.3f * x + ${_b}%.3f "
      }
    }
    
    def makeLinearEqFn(a: Double, b: Double) = {
      type D = Double
      var (_a, _b) = (a, b)
    
      val setB = (b: D) => {_b = b}
    
      LinearEquationFn(
        setA = (a: D) => {_a = a },
        getA = () => _a,
        setB = setB,
        getB = () => _b,
        compute = (x: D) => _a * x + _b
      )
    }
    
    scala> val lineqEsoteric = makeLinearEqFn(3.0, 4.0)
    lineqEsoteric: LinearEquationFn = Linear equation = 3.000 * x + 4.000
    
    scala> lineqEsoteric.getA()
    res83: Double = 3.0
    
    scala> lineqEsoteric.getB()
    res84: Double = 4.0
    
    scala> lineqEsoteric.compute(2)
    res85: Double = 10.0
    
    scala> List(1.0, 2.0, 3.0, 4.0) map lineqEsoteric.compute
    res86: List[Double] = List(7.0, 10.0, 13.0, 16.0)
    
    scala> lineqEsoteric.setA(5.0)
    
    scala> lineqEsoteric.setB(0.0)
    
    scala> lineqEsoteric compute 5.0
    res90: Double = 25.0
    
    scala> List(1.0, 2.0, 3.0, 4.0) map lineqEsoteric.compute
    res89: List[Double] = List(5.0, 10.0, 15.0, 20.0)
    
    1.14.3.3 Update method

    The update method provides an assignment syntax sugar which can be useful for DSLs.

    Example

    class TestUpdate{
      private var _x = 0
    
      def apply() =
        println("Value of x is = " + _x)
    
      def update(x: Int) = {
        _x = x 
        println("x set to " + _x)
      }
      def update(x: Int, y: Int) = {
        _x = x + y
        println("x set to " + _x)
      }
      def update(s: String, value: Object) = {
        println(s"Key $s of hash table set to value = $value")
      }
    }
    

    Testing:

    scala> val u = new TestUpdate()
    u: TestUpdate = TestUpdate@16f1cb2d
    
    scala> u()
    Value of x is = 0
    
    scala> u() = 10
    x set to 10
    
    scala> u()
    Value of x is = 10
    
    scala> u.update(35)
    x set to 35
    
    scala> u()
    Value of x is = 35
    
    scala> u.apply()
    Value of x is = 35
    
    scala>
    
    scala> u.update(5, 10)
    x set to 15
    
    scala> u()
    Value of x is = 15
    
    scala> u("database.url") = "blob"
    Key database.url of hash table set to value = blob
    
    scala> u.update("database.url", "blob")
    Key database.url of hash table set to value = blob
    
    u("character.gui") = new javax.swing.JFrame()
    Key character.gui of hash table set to value = javax.swing.JFrame[frame0 ...
    
    scala> u.update("character.gui", new javax.swing.JFrame())
    Key character.gui of hash table set to value = javax.swing.JFrame ... ... .
    
    1.14.3.4 Implementing C#-like properties

    The update and apply method can be used to create C#-like properties which are shorthands for get and set methods. A motivation to use property or get or setters instead of public fields is the encapsulation as making the internal data private allows changing the class code, the data representation, memory layout; adding validation logic to setters and firing events to GUIs without changing the client code or breaking third-party code.

    // Only the get and set abstract methods needs to be defined.
    trait IProperty[A]{
      def get(): A
      def set(x: A): Unit
      def apply() = get()
      def update(x: A) = set(x)
      def :=(x: A) = set(x)
      override def toString() = get().toString   
    }
    
    object Property{
      def simple[A](init: A) = {
        var _x = init
        new IProperty[A]{      
          def get()     = _x
          def set(x: A) = {_x  = x}
        }
      }
    
      def fromGS[A](getter: => A, setter: A => Unit) = 
        new IProperty[A]{      
          def get()     = getter
          def set(x: A) = setter(x)
        } 
    
      def readOnly[A](getter: => A) =
        new IProperty[A]{      
          def get()     =
            getter      
          def set(x: A) =
            throw new java.lang.IllegalArgumentException("Error: Read-only property.")
        }
    
      def validate(cond: Boolean, msg: String = "Error invalid argument")(action: => Unit) =
        if(cond)
          action
        else
          throw new java.lang.IllegalArgumentException(msg)
    }
    

    Testing and use-case:

    class Product{
      private var _name  = "unnamed"
      private var _price = 0.0
    
      val id = Property.simple(0)
    
      val name = Property.fromGS(
        getter = _name,
        setter = (name: String) =>  Property.validate(name != "", "Name cannot be empty"){
          println("Name set to " + name)
          _name = name
        }
      )
    
      val price = Property.fromGS(
        getter = _price,
        setter = (price: Double) =>  {
          Property.validate(price > 0 , "Price cannot be negative"){
            println("Price set to " + price)
            _price = price
          }
        }    
      )
    }
    
    
    scala> val product = new Product()
    product: Product = Product@209f6b54
    
    scala> product.id
    res20: IProperty[Int] = 0
    
    scala> product.id()
    res21: Int = 0
    
    scala> product.id() = 10
    
    scala> product.id
    res23: IProperty[Int] = 10
    
    scala> product.id := 20
    
    scala> product.id
    res25: IProperty[Int] = 20
    
    // ----- Name property 
    
    scala> product.name
    res18: IProperty[String] = unnamed
    
    cala> product.name() = "coffee"
    Name set to coffee
    
    scala> product.name.get()
    res32: String = coffee
    
    scala> product.name.set("fresh orange juice")
    Name set to fresh orange juice
    
    scala> product.name := "Chilean wine"
    Name set to Chilean wine 
    
    scala> product.name() = ""
    java.lang.IllegalArgumentException: Name cannot be empty
      at Property$.validate(<pastie>:49)
      at Product.$anonfun$name$2(<pastie>:
    
    //---- Price property 
    
    scala> product.price
     res19: IProperty[Double] = 0.0
    
    
    scala> product.price() = 10.0
    Price set to 10.0
    
    scala> product.price := 20.0
    Price set to 20.0
    
    scala> product.price.set(15.0)
    Price set to 15.0
    
    scala> product.price() * 10
    res42: Double = 150.0
    
    scala> product.price.get * 10.0
    res47: Double = 150.0
    
    scala> product.price := -10.0
    java.lang.IllegalArgumentException: Price cannot be negative
      at Property$.validate(<pastie>:49)
      at Product.$anonfun$price$2(<pastie>:29)
      at scala.runtime.java8.JFunction1$mcVD$sp.apply(JFunction1$mcVD$sp.java:12)
      at Property$$anon$2.set(<pastie>:34)
      at IProperty.$colon$eq(<pastie>:18)
      at IProperty.$colon$eq$(<pastie>:18)
      at Property$$anon$2.$colon$eq(<pastie>:32)
      ... 28 elided
    
    
    def showProduct(prod: Product) = {
      println("Product info")
      println("  id    = " + prod.id)
      println("  name  = " + prod.name)
      println("  price = " + prod.price)
    }
    
    
    scala> showProduct(product)
    Product info
      id    = 20
      name  = Chilean wine
      price = 15.0
    
    def updateProperty[A](prop: IProperty[A], fn: A => A) = 
      prop() = fn(prop())
    
    // Adjust price to inflation rate 6.5%
    scala> updateProperty(product.price, (x: Double) => (100.0 + 6.5) / 100.0 * x)
    Price set to 15.975
    

    See also:

    1.14.4 Creating a Class

    class Account(owner: String, id: Int, balanceInit: Int)  {
    
      private var balance = balanceInit
    
      def getBalance() = balance
    
      def getId() = id
    
      def getOwner() = owner
    
      def deposit(amount: Int) = {
        if (amount < 0)
          error("Erro: Invalid operation. Negative amount of money")
        else 
          balance = balance + amount
      }
    
      def withdraw(amount: Int) = amount match {
        case a if a > balance
            => error("Error: Not enough funds to withdraw.")
    
        case a if a < 0
            => error("Erro: Invalid operation. Negative amount of money")
    
        case _ => balance = balance - amount
      }
    
    
      override def toString() = {
        s"Account{id = $id, owner = $owner} = $$ $balance" 
      }
    
    } // End of class Account
    
    
    scala> val account = new Account("Joseph Smith", 10234, 4000)
    account: Account = Account{id = 10234, owner = Joseph Smith} = $ 4000
    
    // type tab after dot (.) to show all fields and methods
    //
    scala> account.
    deposit   getBalance   getId   getOwner   toString   withdraw
    
    scala> account.deposit _
    res228: Int => Unit = <function1>
    
    scala> account.getBalance _
    res229: () => Int = <function0>
    
    scala> account.getId _
    res230: () => Int = <function0>
    
    
    
    scala> account.toString()
    res180: String = Account{id = 10234, owner = Joseph Smith} = $ 4000
    
    scala> account.getClass()
    res181: Class[_ <: Account] = class Account
    
    
    scala> account.withdraw(300)
    
    scala> account
    res188: Account = Account{id = 10234, owner = Joseph Smith} = $ 3700
    
    scala> account.withdraw(10000)
    java.lang.RuntimeException: Error: Not enough funds to withdraw.
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at Account.withdraw(<console>:24)
      ... 32 elided
    
    scala> account.withdraw(-100)
    java.lang.RuntimeException: Erro: Invalid operation. Negative amount of money
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at Account.withdraw(<console>:27)
      ... 32 elided
    
    scala> account
    res191: Account = Account{id = 10234, owner = Joseph Smith} = $ 3700
    
    scala> account.deposit(400)
    
    scala> account
    res193: Account = Account{id = 10234, owner = Joseph Smith} = $ 4100
    
    scala> account.deposit(-400)
    java.lang.RuntimeException: Erro: Invalid operation. Negative amount of money
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at Account.deposit(<console>:17)
      ... 32 elided
    
    
    scala> account.getOwner()
    res225: String = Joseph Smith
    
    scala> account.getId()
    res226: Int = 10234
    

    1.14.5 Inheritance

    Inheritance is useful in GUI programming to create new Widgets derived from existing ones.

    The Button that inherits JButton below has a better initialization and Scala-friendly method to add event handlers (aka Java's listeners).

    • The method onClick returns a function that when executed function with type synonym dispose that when executed removes the event handler.
    import javax.swing._ 
    
    type Dispose = () => Unit
    
    class Button(
      text:    String,
      enabled: Boolean        = true,
      bgColor: java.awt.Color = null,
      fgColor: java.awt.Color = null,
      toolTip: String         = null,
      onClick: => Unit        = ()
    ) extends javax.swing.JButton {
    
      init()
    
      private def init(){
        this.setText(text)
        this.setEnabled(enabled)
        if (bgColor != null) this.setBackground(bgColor)
        if (fgColor != null) this.setForeground(fgColor)
        if (toolTip != null) this.setToolTipText(toolTip)
        this.onClick{ onClick }
      }
    
      def onClick (handler: => Unit): Dispose  = {
        val listener = new java.awt.event.ActionListener(){
          def actionPerformed(evt: java.awt.event.ActionEvent) = {
            handler
          }
        }
        this.addActionListener(listener)
        () => this.removeActionListener(listener)
      }
    }
    
    
    
    val frame = new JFrame("Hello world")
    frame.setSize(400, 300)
    frame.setLayout(new java.awt.FlowLayout())
    
    val button1 = new Button(
      "Click me!",
      // Optional parameters 
      fgColor = java.awt.Color.RED,  // Foreground color 
      bgColor = java.awt.Color.GRAY, // Background color 
      toolTip = "Please click at me"  
    )
    
    val button2 = new Button("Button Exit")
    
    frame.add(button1)
    frame.add(button2)
    frame.setVisible(true)
    
    button1.onClick{
      println("Button 1 clicked")  
    }
    
    button2.onClick{ System.exit(0)}
    

    1.14.6 Class with higher order methods

    Scala classes can have methods that accepts functions as parameters or higher order methods. Note that Scala's collections like List, Array, Map have higher order methods such as Array.map, Array.foreach and so on.

    Example:

    class Pipe[A](value: A){
      def p[B](fn: A => B) = new Pipe(fn(value))
      def get() = value
    }
    
    
    scala> val v = new Pipe(100.0)
    v: Pipe[Double] = Pipe@d8c6f0
    
    scala> v.p(_+10).get
    res41: Double = 110.0
    
    scala> v.p(_+10).p(Math.sin).get
    res42: Double = -0.044242678085070965
    
    scala> v.p(_+10).p(Math.sin).p(Math.cos).get
    res43: Double = 0.9990214523521718
    
    scala> v.p(_+10).p(Math.sin).p(Math.cos).p(x => x * 3).get
    res44: Double = 2.9970643570565154
    
    // Alternative way
    
    scala> v p(_+10) get
    res47: Double = 110.0
    
    scala> v p(_+10) p(Math.sin) p(Math.cos) p(x => x * 3) get
    res48: Double = 2.9970643570565154
    
    { v
      .p(_+10)
      .p(Math.sin)
      .p(Math.cos)
      .p(x => x * 3)
      .get
    }
    
    scala> { v
         |   .p(_+10)
         |   .p(Math.sin)
         |   .p(Math.cos)
         |   .p(x => x * 3)
         |   .get
         | }
    res49: Double = 2.9970643570565154
    
    val out = {
      v
      .p(_+10)
      .p(Math.sin)
      .p(Math.cos)
      .p(x => x * 3)
      .get
    }
    out: Double = 2.9970643570565154
    

    1.14.7 "Operator overloading"

    Note: Scala doesn't have operator overloading since (+), (-) and other math operators are just methods.

    Example: Complex number arithmetic.

    package complex
    
    case class Cpl(re: Double, img: Double){
    
      override def toString() =
        s"${re} + ${img}j"
    
      def unary_-() = 
        Cpl(-this.re, -this.img)
    
      def +(that: Double) = 
        Cpl(this.re + that, this.img)
    
    
      def +(that: Cpl) = 
        Cpl(this.re + that.img, this.img + that.img)
    
    
      def -(that: Double) = 
        Cpl(this.re - that, this.img)
    
    
      def -(that: Cpl) = 
        Cpl(this.re - that.re, this.img - that.img)
    
    
      def *(that: Double) =
        Cpl(that * this.re, that * this.img)
    
      def *(that: Cpl) = {
        val x = this.re * that.re - this.img * that.img
        val y = this.re * that.img + this.img * that.re 
        Cpl(x, y)
        }
    
    
      def /(that: Double) =
        Cpl(this.re / that, this.img / that)
    
      def /(that: Cpl) = {
        val r = that.re * that.re + that.img * that.img
        val x = this.re * that.re + this.img * that.img
        val y = - this.re * that.img + this.img * that.re
        Cpl(x / r, y / r)
      }
    
      // Conjugate 
      def conj =
        Cpl(this.re, -this.img)
    
      def norm = Math.sqrt(re * re + img * img)
    
      // Angle in radians 
      def angle = Math.atan2(img, re)
    
      // Angle in degrees 
      def angled = Math.atan2(img, re) * 180.0 / Math.PI 
    
    }
    
    
    object Complex{
    
      val j = Cpl(0, 1)
    
      implicit class DoubleToCpl(k: Double) {
    
        //def j = Cpl(0, k)
    
        def polr = Cpl(Math.cos(k), Math.sin(k))
    
        def pold = {
          val a = k / 180.0 * Math.PI
          Cpl(Math.cos(a), Math.sin(a))
        }
    
        // k + that
        def +(that: Cpl) = Cpl(that.re + k, that.img)
    
        // k * that 
        def *(that: Cpl) = Cpl(k * that.re, k * that.img)
    
        def -(that: Cpl) = Cpl(k - that.re, -that.img)
    
        // k / that    
        def /(that: Cpl) = {
          val c = that.re * that.re + that.img * that.img
          Cpl( k * that.re / c, - k * that.img / c)
        }
      }
    }
    

    Explanation:

    The expression 4.56 + (10 + 4j) is equivalent to 4.56.add(10 + 4j), that is a Double class method invocation. But implementing the method .add(<complex>) would require modifying the source code of the class Double. As it is not possible, the only way to implement this method is by creating an implicit class "DoubleToCpl" that works as follow: whenever the compiler finds the expression 4.50 + (10 + 4j), it converts the number 4.50, that is an instance of Double class, to the class DoubleTocpl that has a method to carry out complex number addition.

    • (10 + 4j) + 3.50 is the same as:
      • (10 + 4j) add 3.50 or (10 + 4j).add(3.50)
    • 4.56 + (10 + 4j) is the same as:
      • 4.56 add (10 + 4j) or 4.56.add(10 + 4j)

    Testing in the REPL by loading the script.

    scala> :paste src/complex.scala
    Pasting file src/complex.scala...
    
    import complex.Cpl
    import complex.Complex._
    import scala.language.postfixOps
    
    
    // Imaginary unit
    //------------------------
    //
    scala> j
    res0: complex.Cpl = 0.0 + 1.0j
    
    scala> j * j
    res1: complex.Cpl = -1.0 + 0.0j
    
    scala> - j
    res2: complex.Cpl = -0.0 + -1.0j
    
    scala> 6 + 8 * j
    res3: complex.Cpl = 6.0 + 8.0j
    
    
    scala> val c = 6 + 8 * j
    c: complex.Cpl = 6.0 + 8.0j
    
    scala> c.re
    res4: Double = 6.0
    
    scala> c.img
    res5: Double = 8.0
    
    scala> -c
    res9: complex.Cpl = -6.0 + -8.0j
    
    scala> c.conj
    res10: complex.Cpl = 6.0 + -8.0j
    
    scala> c * c.conj
    res12: complex.Cpl = 100.0 + 0.0j
    
    scala> 5 * c
    res14: complex.Cpl = 30.0 + 40.0j
    
    scala> c / 2
    res15: complex.Cpl = 3.0 + 4.0j
    
    scala> Cpl(3.0, 4.0)
    res16: complex.Cpl = 3.0 + 4.0j
    
    scala> Cpl(3.0, 4.0).img
    res17: Double = 4.0
    
    scala> Cpl(3.0, 4.0).norm
    res18: Double = 5.0
    
    scala> Cpl(3.0, 4.0).img
    res17: Double = 4.0
    
    scala> Cpl(3.0, 4.0).norm
    res18: Double = 5.0
    
    
    scala> c / c
    res21: complex.Cpl = 1.0 + 0.0j
    

    Testing in the REPL by compiling the script.

    1. Compile src/complex.scala to a jar file.
    $ scalac src/complex.scala  -d complex.jar 
    
    $ file complex.jar 
    complex.jar: Java archive data (JAR)
    
    $ unzip -l complex.jar
    Archive:  complex.jar
      Length      Date    Time    Name
    ---------  ---------- -----   ----
           57  2017-09-26 02:22   META-INF/MANIFEST.MF
         7057  2017-09-26 02:22   complex/Cpl.class
         1726  2017-09-26 02:22   complex/Cpl$.class
          951  2017-09-26 02:22   complex/Complex.class
          840  2017-09-26 02:22   complex/Complex$.class
         1411  2017-09-26 02:22   complex/Complex$DoubleToCpl.class
    ---------                     -------
        12042                     6 files
    
    1. Load in the REPL
    $ scala  -cp complex.jar 
    Welcome to Scala 2.12.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
    Type in expressions for evaluation. Or try :help.
    
    import complex.Cpl
    import complex.Complex._
    import scala.language.postfixOps
    
    scala> 6 + 8 * j
    res0: complex.Cpl = 6.0 + 8.0j
    
    scala> 6 + 8 * j
    res1: complex.Cpl = 6.0 + 8.0j
    
    scala> (6 + 8 * j) conj
    res2: complex.Cpl = 6.0 + -8.0j
    
    scala> (6 + 8 * j) norm 
    res3: Double = 10.0
    

    1.14.8 Abstract Classs

    An abstract class is a class which cannot be instantiated, containing abstract methods (methods without implementation) and non-abstract methods .It is intended to be a base class or parent class for sub classes that will inherit it.

    Example:

    abstract class Shape {
      val name: String 
      def getArea(): Double
      def getPerimiter(): Double
      def scaleDimensions(factor: Double): Unit
    }
    
    class Rectangle(xx: Double, yy: Double) extends Shape{
      private var x = xx
      private var y = yy
    
      val name = "Rectangle"
    
      def getArea() = x * y
    
      def getPerimiter() = 2.0 * (x + y) 
    
      def scaleDimensions(factor: Double) = {
        x = factor * x
        y = factor * y
      }
    
      def getX() = x
      def getY() = y
      def setX(nx: Double) = { x = nx }
      def setY(ny: Double) = { y = ny }
    
    }
    
    
    class Circle(r: Double) extends Shape{
      private var radius = r
      private val pi = 3.1415
    
      val name = "Circle"
    
      def getArea() = pi * radius * radius
    
      def getPerimiter() = 2.0 * pi * radius
    
      def scaleDimensions(factor: Double) = {
        radius = factor * radius
      }
    
      def getRadius() = radius
    
      def setRadius(r: Double) = { radius = r}
    }
    
    
    
    scala> val rec = new Rectangle(10.0, 20.0)
    rec: Rectangle = Rectangle@8f2e3e6
    
    scala> rec.name
    res9: String = Rectangle
    
    scala> rec.getX()
    res5: Double = 10.0
    
    scala> rec.getY()
    res6: Double = 20.0
    
    scala> rec.getArea()
    res7: Double = 200.0
    
    scala> rec.getPerimiter()
    res8: Double = 60.0
    
    scala> rec.scaleDimensions(2.0)
    
    scala> rec.getX()
    res11: Double = 20.0
    
    scala> rec.getArea()
    res12: Double = 800.0
    
    
    scala> val circ = new Circle(10.0)
    circ: Circle = Circle@169d5567
    
    scala> circ.name
    res13: String = Circle
    
    scala> circ.getArea()
    res14: Double = 314.15000000000003
    
    scala> circ.getPerimiter()
    res15: Double = 62.830000000000005
    
    scala> circ.getRadius()
    res17: Double = 10.0
    
    scala> List(circ, rec)
    res18: List[Shape] = List(Circle@169d5567, Rectangle@8f2e3e6)
    
    scala> List(circ, rec).map(_.name)
    res19: List[String] = List(Circle, Rectangle)
    
    scala> List(circ, rec).map(_.getArea())
    res20: List[Double] = List(314.15000000000003, 800.0)
    
    scala> List(circ, rec).map(_.getArea()).sum
    res21: Double = 1114.15
    
    
    scala> List(circ, rec).map(_.getPerimiter())
    res23: List[Double] = List(62.830000000000005, 120.0)
    
    scala> List(circ, rec).map(_.getPerimiter()).sum
    res24: Double = 182.83
    

    1.14.9 Traits

    Traits are similar to java interfaces. A class can inherit only one class, but can mix multiple traits and must implement the methods and fields of each trait.

    Notes:

    • A trait can have concrete and abstract methods.
    • Traits must not have constructors.
    • Unlike interfaces, traits can have implementation of methods.
    trait Shape {
      def getName(): String
      def getArea(): Double
    }
    
    trait Location {
      var ox: Double
      var oy: Double
      def move(dx: Double, dy: Double): Unit
      def location(): (Double, Double)
    }
    
    class Rectangle(w: Double, h: Double) extends Shape with Location {
      var ox = 0.0
      var oy = 0.0 
      def getName() = "rectangle"
      def getArea() = w * h
    
      def move(dx: Double, dy: Double) = {
        ox = ox + dx
        oy = oy + dy 
      }
    
      def location() = (ox, oy)
    
    }
    
    class Circle(radius: Double) extends Shape with Location {
      var ox = 0.0
      var oy = 0.0 
      def getName() = "circle"
      def getArea() = 3.1415 * radius * radius
    
      def move(dx: Double, dy: Double) = {
        ox = ox + dx
        oy = oy + dy 
      }
    
      def location() = (ox, oy)
    
    }
    
    
    
    
    scala> val rec = new Rectangle(10.0, 20.0)
    rec: Rectangle = Rectangle@29526c05
    
    scala> rec.
    getArea   getName   location   move   ox   oy
    
    scala> rec.getArea()
    res0: Double = 200.0
    
    scala> rec.getName()
    res1: String = rectangle
    
    scala> rec.location()
    res2: (Double, Double) = (0.0,0.0)
    
    scala> rec.move(20.0, 30.0)
    
    scala> rec.location()
    res4: (Double, Double) = (20.0,30.0)
    
    scala> rec.move(0.0, 10.0)
    
    scala> rec.location()
    res6: (Double, Double) = (20.0,40.0)
    
    scala> 
    
    
    scala> val loc: Location = rec
    loc: Location = Rectangle@29526c05
    
    scala> loc.
    location   move   ox   ox_=   oy   oy_=
    
    scala> loc.location()
    res7: (Double, Double) = (20.0,40.0)
    
    scala> loc.ox
    res8: Double = 20.0
    
    scala> loc.oy
    res9: Double = 40.0
    
    scala> loc.getName()
    <console>:17: error: value getName is not a member of Location
           loc.getName()
               ^
    
    
    scala> val circ = new Circle(10.0)
    circ: Circle = Circle@2ecdcfe3
    
    scala> circ.getArea()
    res11: Double = 314.15000000000003
    
    scala> circ.location()
    res12: (Double, Double) = (0.0,0.0)
    
    scala> circ.move(10.0, 30.0)
    
    scala> circ.location()
    res14: (Double, Double) = (10.0,30.0)
    
    scala> circ.move(10.0, 30.0)
    
    scala> circ.location()
    res16: (Double, Double) = (20.0,60.0)
    
    
    
    scala> List(circ, rec).map(_.getArea())
    res17: List[Double] = List(314.15000000000003, 200.0)
    
    scala> List(circ, rec).map(_.location())
    res18: List[(Double, Double)] = List((20.0,60.0), (20.0,40.0))
    
    scala> List(circ, rec).map(_.getName())
    res19: List[String] = List(circle, rectangle)
    
    
    
    def getArea(shape: Shape) = shape.getArea()
    
    scala> getArea(circ)
    res20: Double = 314.15000000000003
    
    scala> getArea(rec)
    res21: Double = 200.0
    
    def getDistance(loc: Location) = Math.sqrt(loc.ox * loc.ox + loc.oy * loc.oy)
    
    scala> getDistance(circ)
    res22: Double = 63.245553203367585
    
    scala> getDistance(rec)
    res23: Double = 44.721359549995796
    
    scala> List(circ, rec).map(getDistance)
    res24: List[Double] = List(63.245553203367585, 44.721359549995796)
    

    1.15 Scala Type System

    1.15.1 Subtyping annotation

    As Scala is an object oriented language, it has subtyping, if the classes B and C are subclasses (aka derived classes) of the class A, then B and C are subtypes of A and any instance (object) of derived classes of A can be supplied where an object of type A is expected.

    So the relations between classes B, C and A can be stated as:

    • A <: B => It means that A is an subtype of B. It can also be said that the type A is upper bounded by B. This subtype relationship happens when a class A inherits a class B.
    • A >: B => A is an supertype of B or that they type A is lower bounded by type B.

    Example:

    // Supertype 
    class TCPProtocol{
      def getName() = "generic TCP/IP protocol"
    }
    
    // Subtypes of TCPProtocol
    class FTP extends TCPProtocol{
      override def getName() = "FTP Protocol"
    }
    
    class HTTP extends TCPProtocol{
      override def getName() = "HTTP Protocol"
      def getMethods()  = List("POST", "GET", "DELETE", "HEAD")
    }
    
    class Webdav extends HTTP{
      override def getName() = "HTTP Protocol extension - Webdav"
      override def getMethods() = super.getMethods() ++ List("COPY", "LOCK", "MOVE")
    }
    
    // Sample client code: 
    def identifyProtocol(prot: TCPProtocol) = {
      println("Network protocol is = " + prot.getName())
    }
    
    // Sample client code with subtyping annotation
    //
    def identifyProtocolSub[P <: TCPProtocol](prot: P) = {
      println("[P] - Network protocol is = " + prot.getName())
    }
    

    Any subtype or subclass of TCPProtocol can be used where an instance of this class is expected such as in the function identifyProtocol which works with the protocols FTP, HTTP and Webdav. The same fact happens with the function identifyHTTPProtocol, it works with any subtype of HTTP such as HTTP and Webdav, but doesn't work with FTP or TCPProtocol. Generalizing what was stated, any subtype of a type can be used where the super type is expected, as reasult any subclass can be used where the parent class or interface is expected.

    // Testing objects
    val tcp = new TCPProtocol()
    val http = new HTTP()
    val webdav = new Webdav()
    
    // The function identifyProtocol works with any subtype of TCPProtocol
    scala> identifyProtocol(tcp)
    Network protocol is = generic TCP/IP protocol
    
    scala> identifyProtocol(ftp)
    Network protocol is = FTP Protocol
    
    scala> identifyProtocol(http)
    Network protocol is = HTTP Protocol
    
    scala> identifyProtocol(webdav)
    Network protocol is = HTTP Protocol extension - Webdav
    
    
    scala> identifyProtocolSub(tcp)
    [P] - Network protocol is = generic TCP/IP protocol
    
    scala> identifyProtocolSub(http)
    [P] - Network protocol is = HTTP Protocol
    
    scala> identifyProtocolSub(webdav)
    [P] - Network protocol is = HTTP Protocol extension - Webdav
    
    scala> val protocolList = List(http, webdav, tcp)
    protocolList: List[TCPProtocol] = List(HTTP@dffcf1, Webdav@519e14f6, TCPProtocol@6d2f910b)
    
    scala> protocolList foreach identifyProtocolSub
    [P] - Network protocol is = HTTP Protocol
    [P] - Network protocol is = HTTP Protocol extension - Webdav
    [P] - Network protocol is = generic TCP/IP protocol
    
    // This function only accepts 
    // instances of HTTP or instances of its subclasses 
    def identifyHTTPProtocol(prot: HTTP) = { 
      println("HTTP Protocol = " + prot.getName())
      println("HTTP Methods  = " + prot.getMethods())
    }
    
    scala> identifyHTTPProtocol(webdav)
    HTTP Protocol = HTTP Protocol extension - Webdav
    HTTP Methods  = List(POST, GET, DELETE, HEAD, COPY, LOCK, MOVE)
    
    scala> identifyHTTPProtocol(tcp)
    <console>:19: error: type mismatch;
     found   : TCPProtocol
     required: HTTP
      identifyHTTPProtocol(tcp)
    ^
    

    1.15.2 Variance

    Variance is the relationship between subytpes of parametrized types or type constructos and subtypes of types parameters.

    The relationship between the type constructor F[ ] and its type parameter T can be described as:

    • Covariance
      • Notation: F[+T]
      • The type constructor F is covariant at parameter T if:
        • A <: B implies that F[A] <: F[B]
        • A <: B means that A is a subtype of B
        • F[A] <: F[B] means that F[A] is a subtype of F[B]
    • Contravariance
      • Notation: F[-T]
      • F[-A]
      • The type constructor F is contravarint at parameter T if:
        • A <: B (A is a subytpe of B) implies that F[B] <: F[A]
    • Invariance => Invariant type constructor
      • F[T]
      • None of the relationship applies for the type constructor F at parameter T. So there is any type relationship between two types F[A] and F[B] when A <: B, A is an subtype of B.

    Note:

    • F[A <: B] denotes that the type constructor F can take any type parameter (or class) wich is a subtype of B. It doesn't have the same meaning.
      • case class F[T <: Shape](t: T) … The parameter A of this the tyep constructor F can take any argument t wich is subtype of Shape, it can be a derived trait, derived class or case object.
    • F[+T] means that that if an class A is a subtype of class B, then the type F[A] will be a subtype of F[B].
      • case class F[+T](t: T)

    Example:

    Sample experimentation classes:

    trait Vehicle{
      def getName(): String
      def getType(): String 
      def getID():   Int
      override def toString() =
        s"Vehicle type = ${getName()} / name = ${getName()}"
    }
    
    class Car(name: String) extends Vehicle{
      def getName() = name 
      def getType() = "car"
      def getID() = 20 
    }
    
    class OilTanker(name: String) extends Vehicle{
      def getName() = name
      def getType() = "Oil Tanker"
      def getID() = 251
    }
    
    val carArray = Array(new Car("model1"), new Car("model2"), new Car("model2"))
    val tankerArray = Array(new OilTanker("FPSO X4AKT2"), new OilTanker("FPSO M4A372"))
    
    val car1    = new Car("Model X")
    val tanker1 = new OilTanker("Super oil carrier")
    

    Experiments:

    • Array (same as Java's array []) is an invariant type, thre is no type relationship between Array[Vehicle] and Array[Car]
    // Java Array is invariant: The following code will not work
    // because Array[Car] is not a subtype of vehicle.
    //
    
    def countPortfolio(xs: Array[Vehicle]) =
      println("Number of items is equal to " + xs.length)
    
    scala> countPortfolio(carArray)
    <console>:14: error: type mismatch;
     found   : Array[Car]
     required: Array[Vehicle]
    Note: Car <: Vehicle, but class Array is invariant in type T.
    You may wish to investigate a wildcard type such as `_ <: Vehicle`. (SLS 3.2.10)
           countPortfolio(carArray)
                          ^
    // It only works with exactly Array[Vehicle]
    scala> countPortfolio(carArray.asInstanceOf[Array[Vehicle]])
    Number of items is equal to 3
    
    • Scala's list is covariant as List[Car] is a subtype of List[Vehicle].
    def countPortfolio2(xs: List[Vehicle]) =
      println("Number of items is equal to " + xs.length)
    
    scala> val vehicleList = List(new Car("m1"), new OilTanker("FPSO AXPF"), new Car("m3"))
    vehicleList: List[Vehicle] = List(Vehicle type = m1 / name = m1,  ... )
    
    scala> val carList = List(new Car("m1"), new Car("m3"))
    carList: List[Car] = List(Vehicle type = m1 / name = m1, Vehicle type = m3 / name = m3)
    
    scala> countPortfolio2(vehicleList)
    Number of items is equal to 3
    
    scala> countPortfolio2(carList)
    Number of items is equal to 2
    
    • The type constructor Container1 is invariant for type parameter A, therefore the function showContainer will only work with type showContainer.
    // type Container1 is invariant at parameter A
    trait Container1[A]{
      def get(): A
    }
    
    def showContainer1(cont: Container1[Vehicle]) =
      println("Container = " + cont.get())
    
    scala> val cont1 = new Container1[Vehicle]{ def get() = car1 }
    cont3: Container1[Vehicle]{def get(): Car} = $anon$1@1cab1e3d
    
    scala> val cont2 = new Container1[Car]{ def get() = car1 }
    cont2: Container1[Car] = $anon$1@2b3e1279
    
    scala> showContainer1(cont1)
    Container = Vehicle type = Model X / name = Model X
    
    scala> showContainer1(cont2)
    <console>:14: error: type mismatch;
     found   : Container1[Car]
     required: Container1[Vehicle]
    Note: Car <: Vehicle, but trait Container1 is invariant in type A.
    You may wish to define A as +A instead. (SLS 4.5)
           showContainer1(cont2)
                          ^
    
    • The type constructor Container2 is covariant for type parameter A, as a result the function showContainer2 will work with any subtype of Vehicle.
    // Type Container2 is variant at parameter A
    trait Container2[+A]{
      def get(): A
    }
    
    def showContainer2(cont: Container2[Vehicle]) =
      println("Container = " + cont.get())
    
    scala> val cont1b = new Container2[Vehicle]{ def get() = car1 }
    cont1b: Container2[Vehicle]{def get(): Car} = $anon$1@6bbaf0db
    
    scala> val cont2b = new Container2[Car]{ def get() = car1 }
    cont2b: Container2[Car] = $anon$1@52dd3c57
    
    scala> showContainer2(cont1b)
    Container = Vehicle type = Model X / name = Model X
    
    scala> showContainer2(cont2b)
    Container = Vehicle type = Model X / name = Model X
    

    Further Reading

    1.16 Scala Implicit

    1.16.1 Use Cases

    Use Cases:

    • Implict type conversion.
    • Implicit conversions of Functions to Single-Method Interfaces
    • Class Extension
    • Type Classes

    1.16.2 Implicit type conversion

    1.16.2.1 Overview

    Allows the compiler to implict convert a type A to another B where the type B is needed and a type A is supplied. Example: convert a integer 3 values tuple to Date object wherever is necessary a data object.

    1.16.2.2 Converting Tuple to LocalDate
    object DateTuple {
    
      import java.time.LocalDate
    
      implicit def tupleToDate(tpl: (Int, Int, Int)) = {
        val (y, m, d) = tpl
        LocalDate.of(y, m, d)
      }
    }
    
    
    //---------- Before importing DateTuple object / module ---------- //
    
    /// Java 8 Date API 
    scala> java.time.LocalDate.of(2010, 10, 1)
    res83: java.time.LocalDate = 2010-10-01
    
    
    scala> (2010, 10, 1): java.time.LocalDate
    <console>:12: error: type mismatch;
     found   : (Int, Int, Int)
     required: java.time.LocalDate
           (2010, 10, 1): java.time.LocalDate
           ^
    
    scala> (2010, 10, 1).getYear()
    <console>:12: error: value getYear is not a member of (Int, Int, Int)
           (2010, 10, 1).getYear()
    
    
    //---------- After importing DateTuple object -----------------------//
    
    scala> import DateTuple._
    import DateTuple._
    
    scala> (2010, 10, 1)
    res22: (Int, Int, Int) = (2010,10,1)
    
    // Compiler converts triple tuple to local date 
    scala> (2010, 10, 1): java.time.LocalDate
    res6: java.time.LocalDate = 2010-10-01
    
    // Compiler converts triple tuple to local date and invokes the method getYear.
    scala> (2010, 10, 1).getYear
    res10: Int = 2010
    
    scala> (2010, 10, 1).getMonth
    res11: java.time.Month = OCTOBER
    
    scala> (2010, 10, 1).getDayOfMonth
    res12: Int = 1
    
    scala> (2010, 10, 1).getDayOfYear
    res13: Int = 274
    
    scala> List((2010, 10, 1), (1998, 10, 1), (2002, 4, 5)) map (_.getYear)
    res14: List[Int] = List(2010, 1998, 2002)
    
    
    
    scala> import java.time.LocalDate 
    import java.time.LocalDate
    
    scala> val d1 = (2001, 10, 1): LocalDate
    d1: java.time.LocalDate = 2001-10-01
    
    scala> val d2 : LocalDate = (2001, 10, 1)
    d2: java.time.LocalDate = 2001-10-01
    
    scala> d1.getYear()
    res15: Int = 2001
    
    scala> d2.getYear()
    res16: Int = 2001
    
    scala> d1 == d2
    res17: Boolean = true
    
    
    cala> def addDays(ndays: Int, d: java.time.LocalDate) = d.plusDays(ndays)
    addDays: (ndays: Int, d: java.time.LocalDate)java.time.LocalDate
    
    scala> addDays(10, java.time.LocalDate.of(2001, 10, 1))
    res19: java.time.LocalDate = 2001-10-11
    
    scala> addDays(10, (2001, 10, 1))
    res20: java.time.LocalDate = 2001-10-11
    
    scala> val t = (2001, 10, 1)
    t: (Int, Int, Int) = (2001,10,1)
    
    scala> addDays(10, t)
    res21: java.time.LocalDate = 2001-10-11
    

    1.16.3 Implicit conversions of Functions to Single-Method Interfaces

    1.16.3.1 Overview

    Java has many single method-interfaces such as ActionListener, Runnable, Callable and etc which require a verbose instantiation of anonymous classes of those interfaces.

    Scala implicit type conversion can make the code shorter by eliminating the need for instatiation of single-method interface through implicit converting a function to an anonymous class which implementing this single-method interface. For instance, it allows a function be passed as an argument to a method that requires an ActionListener or a Runnable interface.

    As can be seen in the codes below all single-methods interfaces could be replaced by functions.

    Runnable Interface:

    interface Runnable{ 
        public void run();
    }
    

    ActionListener

    interface ActionListener{
        public void actionPerformed(ActionEvent e);
    }
    
    1.16.3.2 Converting Functions to Java Swing Event Listener

    In the code below, the object (module) FunctionToListener provides functions that converts click event handler functions to ActionListener required by the JButton method addActionListener.

    object FunctionToListener{
      import java.awt.event.{ActionEvent, ActionListener}
    
      implicit def funToActionListener1(handler: ActionEvent => Unit) = {
        new ActionListener(){
          def actionPerformed(evt: ActionEvent) = handler(evt)
        }
      }
    
      implicit def funToActionListener2(handler: () => Unit) = {
        new ActionListener(){
          def actionPerformed(evt: ActionEvent) = handler()
        }
      }
    
      implicit def funToActionListener3(handler: => Unit) = {
        new ActionListener(){
          def actionPerformed(evt: ActionEvent) = handler
        }
      }
    
    } //------- End of object FunctionToListener ------- //
    
    
    import javax.swing.{JFrame, JButton}
    import java.awt.event.{ActionEvent, ActionListener}
    
    val btn = new JButton("Click me")
    val frame = new JFrame("Hello world")
    frame.setSize(400, 500)
    frame.setLayout(new java.awt.FlowLayout())
    frame.add(btn)
    frame.setVisible(true)
    
    // -------- Before importing FunctionToListener  --------- //
    
    
    scala> btn.addActionListener _ 
    res6: java.awt.event.ActionListener => Unit = $$Lambda$1404/1838333871@a23b96b
    
    // Error!
    scala> btn.addActionListener(() => println("I was clicked"))
    <console>:14: error: type mismatch;
     found   : () => Unit
     required: java.awt.event.ActionListener
           btn.addActionListener(() => println("I was clicked"))
    
    // Error! 
    scala>  btn.addActionListener{ println("I was clicked")}
    <console>:15: error: type mismatch;
     found   : Unit
     required: java.awt.event.ActionListener
            btn.addActionListener{ println("I was clicked")}
    
    
    // -------- After importing FunctionToListener  --------- //
    
    import FunctionToListener._
    
    btn.addActionListener(() => println("Handler1: I was clicked"))
    
    btn.addActionListener{
      println("Handler2: I was clicked")
    }
    
    btn.addActionListener{ (evt: ActionEvent) =>
      println("Handler3: I was clicked ")
    }
    
    // User clicks at the button ...
    scala> Handler3: I was clicked 
    Handler2: I was clicked
    Handler1: I was clicked
    Handler3: I was clicked 
    Handler2: I was clicked
    Handler1: I was clicked
    Handler3: I was clicked 
    Handler2: I was clicked
      ... ... ... ...
    
    
    scala> val hnd: ActionListener = println("Hello Java")
    hnd: java.awt.event.ActionListener = FunctionToListener$$anon$3@28dd038f
    
    scala> val hnd2: ActionListener = () => println("Hello Java")
    hnd2: java.awt.event.ActionListener = FunctionToListener$$anon$2@4ca6f587
    
    1.16.3.3 Converting code block to Runnable
    object BlockToRunnable {
    
      /** Converts a code block to a Runnable instance */
      implicit def funToRunnable(action: => Unit) = {
        new Runnable(){
          def run() = action
        }
      }
    
    }
    
    
    //--------- Before Import the Helper object -------------- //
    //
    
    val th = new Thread(
      while(true){
        println("I will run every 1 second")
        Thread.sleep(1000)
    })
    
    
    scala> val th = new Thread(
         |   while(true){
         |     println("I will run every 1 second")
         |     Thread.sleep(1000)
         | })
    <console>:11: error: overloaded method constructor Thread with alternatives:
      (x$1: String)Thread <and>
      (x$1: Runnable)Thread
     cannot be applied to (Unit)
           val th = new Thread(
    
    
    //--------- After Import the Helper object -------------- //
    //
    
    scala> import BlockToRunnable._
    import BlockToRunnable._
    
    // Now it works!!         
    scala> val th = new Thread(
         |   while(true){
         |     println("I will run every 1 second")
         |     Thread.sleep(1000)
         | })
    th: Thread = Thread[Thread-4,5,main]
    
    
    scala> th.start()
    
    scala> I will run every 1 second
    I will run every 1 second
    I will run every 1 second
    I will run every 1 second
    I will run every 1 second
    I will run every 1 second
    I will run every 1 second
      ... ... ... ...
    
    
    // A code block can be cast to runnable                  
    val block : Runnable = {
      while(true){
        println("I will run every 1 second")
        Thread.sleep(1000)
      }
    }
    
    scala> block.run _
    res0: () => Unit = $$Lambda$1311/1798538641@277474fc
    
    scala> block.run()
    I will run every 1 second
    I will run every 1 second
    I will run every 1 second
    I will run every 1 second
    

    1.16.4 Extension methods

    1.16.4.1 Overview

    It is useful to add new functionality to code defined in libraries and sources that cannot be modified in a type-safe way.

    1.16.4.2 String class extension to parse Dates

    The String class extension, DateStr defines the methods toDate, toDateMDY and toDateMDY that can parse date strings.

    object DateParsers { 
    
      // International - ISO 8601 standard Date Format
      val dateFormatYMD = new java.text.SimpleDateFormat("yyyy-mm-dd")
    
      // American Date Format 
      val dateFormatMDY = new java.text.SimpleDateFormat("mm-dd-yyyy")
    
      val dateFormatDMY = new java.text.SimpleDateFormat("dd-mm-yyyy")
    
      implicit class DateStr(s: String){
        def toDate()    = dateFormatYMD.parse(s)
        def toDateMDY() = dateFormatMDY.parse(s)
        def toDateDMY() = dateFormatDMY.parse(s)
      }
    
    }
    
    
    scala> import DateParsers._
    import DateParsers._
    
    
    scala> "2015-10-01".toDate
    res58: java.util.Date = Thu Jan 01 00:10:00 BRT 2015
    
    scala> "10-01-2015".toDateMDY
    res61: java.util.Date = Thu Jan 01 00:10:00 BRT 2015
    
    scala> "2015-10-01".toDate == "10-01-2015".toDateMDY
    res62: Boolean = true
    
    scala> "01-10-2015".toDateDMY == "10-01-2015".toDateMDY
    res63: Boolean = true
    
    scala> List("01-01-1970", "02-03-2001", "10-10-2002").map(_.toDate)
    res66: List[java.util.Date] = List(Mon May 24 00:01:00 BRT 6, Fri Jun 24 00:03:00 BRT 7, Tue Jun 25 00:10:00 BRT 15)
    
    scala> List("01-01-1970", "02-03-2001", "10-10-2002").map(_.toDate).foreach(println)
    Mon May 24 00:01:00 BRT 6
    Fri Jun 24 00:03:00 BRT 7
    Tue Jun 25 00:10:00 BRT 15
    
    
    scala> val s : DateStr = "2001-10-01" 
    s: DateParsers.DateStr = DateParsers$DateStr@32d87fe1
    
    scala> s.toDate // Type Tab to complete 
    toDate   toDateDMY   toDateMDY
    
    scala> s.toDate
    res68: java.util.Date = Mon Jan 01 00:10:00 BRT 2001
    
    1.16.4.3 Extension to print elements.
    object PrintHelpers {
      implicit class Printable (x: Any) {
        def printn() = println(x)
      }
    
      implicit class PrintSeq[A](seq: Seq[A]){
        def printAll() = seq foreach println
      }
    
      implicit class PrintableArray[A](xs: Array[A]){
        def printAll() = xs foreach println
      }
    
      implicit class PrintableList[A](xs: List[A]){
        def printAll() = xs foreach println
      }
    }
    
    scala> 100 printn()
    100
    
    scala> "hello world" printn()
    hello world
    
    scala> List(1, 2, 3, 5) printn()
    List(1, 2, 3, 5)
    
    
    
    scala> List(1, 2, 3, 4).printAll()
    1
    2
    3
    4
    
    scala> Array(1, 2, 3, 4).printAll()
    1
    2
    3
    4
    
    scala> val xs: Seq[Int] = List(1, 2, 4, 5)
    xs: Seq[Int] = List(1, 2, 4, 5)
    
    scala> xs.printAll()
    1
    2
    4
    5
    
    
    scala> new java.io.File("/").listFiles().printAll()
    /home
    /var
    /bin
    /usr
    /root
    /Applications
    ... ...
    
    1.16.4.4 Reverse function application

    The implicit class Apply allows the compiler convert any Scala object to this class whenever the method ap is invoked. The class Apply can be used to peform reverse function application like the F# and OCaml operator (|>).

    object ApplyHelper{
      implicit class Apply[A](x: A){
        def ap[B](f: A => B) = f(x)
      }
    }
    
    scala> import ApplyHelper._
    import ApplyHelper._
    
    scala> "hello world" ap println
    hello world
    
    
    scala> val s = "hello world" : Apply[String]
    s: ApplyHelper.Apply[String] = ApplyHelper$Apply@3fa2c8e7
    
    scala> s.ap(println)
    hello world
    
    scala> s ap println
    hello world
    
    
    scala> 1000.0 ap Math.log10
    res24: Double = 3.0
    
    scala> 1000.0 ap Math.log10 ap Math.exp
    res26: Double = 20.085536923187668
    
    scala> 1000.0 ap Math.log10 ap Math.exp ap Math.log
    res27: Double = 3.0
    
    scala> 1000.0 ap Math.log10 ap Math.exp ap Math.log ap println
    3.0
    
    scala> new java.io.File("/") ap (_.listFiles) ap(_.foreach(println))
    /home
    /var
    /bin
    /usr
    /root
    /Applications
    /proc
    /boot
    /dev
    ... .... ...
    

    1.16.5 Implicit parameter passing - basic

    Methods or functions with implicit parameters can be called passing an implicit value in the scope when the parameters marked as implicit are not provided.

    @ def mulBy(x: Int)(implicit y: Int) = x * y 
    defined function mulBy
    
    @ mulBy(10)(5)  
    res1: Int = 50
    
    @ mulBy(10)(2)  
    res2: Int = 20
    

    Before supplying an implicit value: It fails because there is no implicit value in the scope of type int.

    @ mulBy(10) 
    cmd3.sc:1: could not find implicit value for parameter y: Int
    val res3 = mulBy(10)
                    ^
    Compilation Failed
    

    After supplying an implicit value: The implicit value a is passed to the function mulBy implicitly.

    // The name of the implicita parameter doesn't matter. 
    // The compiler looks for the implicit parameter of type int 
    // at the current context.
    //-----------------------------------------------------------
    @ implicit val a = 10 
    a: Int = 10
    
    // y = 10 
    @ mulBy(10) 
    res4: Int = 100
    // y = 10
    @ mulBy(3) 
    res5: Int = 30
    // y = 2 
    @ mulBy(3)(2) 
    res6: Int = 6
    
    // The implicit parameter can be supplied only once.
    scala> implicit val x = 5
    x: Int = 5
    
    scala> mulBy(4)
    <console>:15: error: ambiguous implicit values:
     both value a of type => Int
     and value x of type => Int
     match expected type Int
           mulBy(4)
    

    Implicit parameters and escope:

    • Note: There can be only one implicit parameter of a single type.
    // Restart experiment by exiting REPL and restarting again. 
    //
    
    def mulBy(x: Int)(implicit y: Int) = x * y 
    
    scala> mulBy(10)
    <console>:13: error: could not find implicit value for parameter y: Int
           mulBy(10)
    
    {  
      println("mulBy(10) = " + mulBy(10))
      println("mulBy(4) = " + mulBy(4))
    }
    
    scala> {  
         |   println("mulBy(10) = " + mulBy(10))
         |   println("mulBy(4) = " + mulBy(4))
         | }
    <console>:14: error: could not find implicit value for parameter y: Int
             println("mulBy(10) = " + mulBy(10))
                                           ^
    <console>:15: error: could not find implicit value for parameter y: Int
             println("mulBy(4) = " + mulBy(4))
    
    
    // Supply implicit value at local scope 
    {
      implicit val a = 5
      println("mulBy(10) = " + mulBy(10))
      println("mulBy(4) = " + mulBy(4))
    }
    
    scala> {
         |   implicit val a = 5
         |   println("mulBy(10) = " + mulBy(10))
         |   println("mulBy(4) = " + mulBy(4))
         | }
    mulBy(10) = 50
    mulBy(4) = 20
    
    
    // Supply implicit value at local scope (y = 6)
    {
      implicit val k = 6
      println("mulBy(10) = " + mulBy(10))
      println("mulBy(4) = " + mulBy(4))
    }
    
    scala> {
         |   implicit val k = 6
         |   println("mulBy(10) = " + mulBy(10))
         |   println("mulBy(4) = " + mulBy(4))
         | }
    mulBy(10) = 60
    mulBy(4) = 24
    
    def computeWithImplicit(k: Int) = {
      implicit val y = k 
      println("mulBy(10) = " + mulBy(10))
      println("mulBy(4) = " + mulBy(4))
    }
    
    scala> computeWithImplicit(3)
    mulBy(10) = 30
    mulBy(4) = 12
    
    scala> computeWithImplicit(4)
    mulBy(10) = 40
    mulBy(4) = 16
    

    Multiple Implicit Values:

    def tellYourName(implicit name: String, surname: String) = 
    
    scala> tellNameAndID(200, "Somebody else")
    Name of user = Somebody else, user ID = 200
    
    scala> tellNameAndID
    <console>:13: error: could not find implicit value for parameter userID: Int
           tellNameAndID
    
    {
      implicit val a = 200
      implicit val x = "John Ghost"
      tellNameAndID
    }
    
    scala> {
         |   implicit val a = 200
         |   implicit val x = "John Ghost"
         |   tellNameAndID
         | }
    Name of user = John Ghost, user ID = 200
    
    {
      implicit val a = 25
      implicit val x = "Dummy Test User"
      tellNameAndID
    }
    
    scala> {
         |   implicit val a = 25
         |   implicit val x = "Dummy Test User"
         |   tellNameAndID
         | }
    Name of user = Dummy Test User, user ID = 25
    
    
    // There can be only one implicit value of a given type.
    // More than one int implicit value will generate an compile
    // error. 
    {
      implicit val a = 25
      implicit val z = 10
      implicit val x = "Dummy Test User"
      tellNameAndID
    }
    
    scala> {
         |   implicit val a = 25
         |   implicit val z = 10
         |   implicit val x = "Dummy Test User"
         |   tellNameAndID
         | }
    <console>:17: error: ambiguous implicit values:
     both value z of type Int
     and value a of type Int
     match expected type Int
             tellNameAndID
    

    1.17 OO - Design Patterns

    1.17.1 Overview

    GOF - Gang of Four Design Patterns or Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Publishing Company, 1995)

    Design Patterns

    • Creational Pattern - Patterns concerned with object instatiation/creation.
      • Factory pattern
        • Simple Factory
        • Factory Method
    • Behavioral Patterns - Patterns that focus on communication between objects.
      • Strategy Pattern - Allows switching algorithm/strategy at run-time.
      • Observer / Publisher-Subscriber
    • Structural - Patterns fucusing on objects composition to extend its functionality.

    Creational Patterns

    Factory Pattern

    • Intent: Instantiate classes with a common parent class or interface without specifying a concrete class.

    Singleton

    • Intent: Ensure that a class with only one instance.

    Structural Patterns

    Facade Pattern

    • Provide a unified and simplified interface to a complex subsystem.

    Behavioral Patterns

    Strategy Pattern

    • Intent: Encapsulate algorithms with objects and switch them at run-time.

    Observer Pattern

    • Intent: Define one-to-many dependency between objects.
    • Known uses: Event driven-systems such as GUIs such as Gtk, QT and Java Swing events or Model in model view controller pattern.

    Iterator Pattern

    • Intent: Access elements of a container without exposing its representation.
    • Known uses: Java Iterators, C++ STL iterators.

    1.17.2 Creational Design Patterns

    1.17.2.1 Singleton Design Pattern

    Singleton is a creational design pattern where there is only a single instance of a class and the client code is not allowed to create more instances.

    Example: As the singleton pattern is already a language feature of Scala, it will be shown first the Java implementation of the pattern and then the Scala implementation.

    File: Singleton.java

    public class Singleton{
        private static Singleton _instance = new Singleton();
        private String _name = "unnamed";
    
        public void setName(String name){
            _name = name;
        }
    
        public void service1(){
            System.out.println("Hello world user: " + _name);
            System.out.println("Scala is much better than Java!");
        }
    
        public static Singleton getInstance(){
            return _instance;
        }
    }
    
    • Compiling and running:
    # Compile Singleton.java to generate Singleton.class
    #
    $ javac Singleton.java
    
    # Run Scala REPL and play with compiled Java code.
    #
    $ scala
    Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_162).
    Type in expressions for evaluation. Or try :help.
    
    scala> val s = new Singleton()
    <console>:11: error: trait Singleton is abstract; cannot be instantiated
           val s = new Singleton()
                   ^
    
    scala> val s = Singleton.getInstance()
    s: Singleton = Singleton@517a2b0
    
    scala> s.service1()
    Hello world user: unnamed
    Scala is much better than Java!
    
    scala> s.setName("Somebody else")
    
    scala> s.service1()
    Hello world user: Somebody else
    Scala is much better than Java!
    
    scala> val s2 = Singleton.getInstance()
    s2: Singleton = Singleton@517a2b0
    
    scala> s2.service1()
    Hello world user: Somebody else
    Scala is much better than Java!
    
    # Check if s2 and s have the same reference, point to the same 
    # memory location. 
    scala> s2 == s
    res3: Boolean = true
    
    scala> s2.service1()
    Hello world user: Somebody else
    Scala is much better than Java!
    

    Scala way: In Scala, there are no static methods or static classes (classes only with static methods), however they can be replaced by the singleton created with the "object" keyword.

    object SingletonScala{
      // It could be: private var _name = "unnamed"
      private var _name: String = "unnamed"
    
      def setName(name: String) =
        _name = name
    
      def service1() = {
        println("Hello world user: " + _name)
        System.out.println("Scala is much better than Java!")
      }
    }
    

    Testing in REPL:

    scala> SingletonScala.service1()
    Hello world user: unnamed
    Scala is much better than Java!
    
    scala> SingletonScala.setName("Thor")
    
    scala> val ss1 = SingletonScala
    ss1: SingletonScala.type = SingletonScala$@12811f95
    
    scala> ss1.service1()
    Hello world user: Thor
    Scala is much better than Java!
    
    // Reference equality, aka identity equality 
    scala> ss1 == SingletonScala
    res9: Boolean = true
    

    The Java code mentioned before could be emulated in this way:

    class Singleton2 private {
      private var _name: String = "unnamed"
    
      def setName(name: String) =
          _name = name
    
      def service1() = {
        println("Hello world user: " + _name)
        System.out.println("Scala is much better than Java!")
      }
    }
    
    object Singleton2{
      private val instance =
        new Singleton2()
    
      def getInstance() =
        instance
    }
    

    Testing:

    //  Copy class Singleton2 and companion object Singleton2 paste them together 
    //  with command (:paste) in Scala REPL.
    //
    :paste
    
    scala> val ssa = new Singleton2()
    <console>:13: error: constructor Singleton2 in class Singleton2 cannot be accessed in object $iw
           val ssa = new Singleton2()
                     ^
    
    scala> val ssa = Singleton2.getInstance()
    ssa: Singleton2 = Singleton2@71d6e503
    
    scala> ssa.service1()
    Hello world user: unnamed
    Scala is much better than Java!
    
    scala> ssa.setName("Someone")
    
    scala> ssa.service1()
    Hello world user: Someone
    Scala is much better than Java!
    
    scala> val ssb = Singleton2.getInstance()
    ssb: Singleton2 = Singleton2@71d6e503
    
    scala> ssb.service1()
    Hello world user: Someone
    Scala is much better than Java!
    
    1.17.2.2 Simple factory pattern

    Defined by GOF as: "Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses."

    The factory pattern is used to create instances of different subclasses of a class. A factory class instantiates a subclass based on the input passed to the factory.

    Parts:

    • Product - Parent class which subclasses will be instantiated by the factory.
    • Factory - Class that instantiate product subclasses.

    The class ComputerFactory is used to instantiate classes that implements the trait (interface) based on the input passed to the factory.

    Note: This pattern is not extensible since, the class ComputerFactory needs to be modified for every new Computer subclass.

    trait Computer {
      def getManufacturer(): String
      def getID(): Int
      def clockGHZ: Int
    
      override def toString() = {
        val m  = getManufacturer()
        val id = getID()
        s"{ Manufacturer = $m id = $id clock = $clockGHZ }"
      }
    }
    
    class ComputerA extends Computer {
      def getManufacturer() = "SunJitsu"
      def getID()  = 100
      def clockGHZ = 4
    }
    
    
    class ComputerB extends Computer {
      def getManufacturer() = "some manufacturer"
      def getID()  = 300
      def clockGHZ = 100
    }
    
    
    class ComputerC extends Computer {
      def getManufacturer() = "unknown manufacturer"
      def getID()  = 350
      def clockGHZ = 4
    }
    
    class ComputerFactory() {
      def getComputer(comp: String) = comp match {
        case "compA" => new ComputerA()
        case "compB" => new ComputerB()
        case "compC" => new ComputerC()
        case _       => error("Error: This type of computer doesn't exist")
      }
    }
    
    
    scala> val factory = new ComputerFactory()
    factory: ComputerFactory = ComputerFactory@6acb0d0d
    
    scala> val compA = factory.getComputer("compA")
    compA: Computer = { Manufacturer = SunJitsu id = 100 clock = 4 }
    
    scala> compA.getManufacturer()
    res29: String = SunJitsu
    
    scala> compA.getID()
    res30: Int = 100
    
    scala> 
    
    
    scala> val compB = factory.getComputer("compB")
    compB: Computer = { Manufacturer = some manufacturer id = 300 clock = 100 }
    
    scala> val compC = factory.getComputer("compC")
    compC: Computer = { Manufacturer = unknown manufacturer id = 350 clok = 4 }
    
    scala> factory.getComputer("comp")
    java.lang.RuntimeException: Error: This type of computer doesn't exist
      at scala.sys.package$.error(package.scala:27)
      at scala.Predef$.error(Predef.scala:144)
      at ComputerFactory.getComputer(<console>:20)
      ... 32 elided
    
    
    scala> List(compA, compB, compC)
    res34: List[Computer] = List({ Manufacturer = SunJitsu id = 100 clok = 4 }, { Manufacturer = some manufacturer id = 300 clok = 100 }, { Manufacturer = unknown manufacturer id = 350 clok = 4 })
    
    
    scala> List(compA, compB, compC).foreach(println)
    { Manufacturer = SunJitsu id = 100 clok = 4 }
    { Manufacturer = some manufacturer id = 300 clok = 100 }
    { Manufacturer = unknown manufacturer id = 350 clok = 4 }
    
    
    scala> List(compA, compB, compC).map(_.getID())
    res42: List[Int] = List(100, 300, 350)
    

    Functional Simplification: The factory class can replaces by a function that instantiates the product sub classes.

    def getComputer(comp: String) = comp match {
      case "compA" => new ComputerA()
      case "compB" => new ComputerB()
      case "compC" => new ComputerC()
      case _       => error("Error: This type of computer doesn't exist")
    }
    
    scala> getComputer _
    res46: String => Computer = <function1>
    
    
    scala> getComputer("compA")
    res47: Computer = { Manufacturer = SunJitsu id = 100 clock = 4 }
    

    References:

    1.17.2.3 Factory pattern with factory method

    This variation allows multiple subclasses be added to the factory.

    trait DatabaseDriver {
      def dbname: String
      def connect(Uri: String): Unit
      def createDriver(): DatabaseDriver
    }
    
    class DbSqlite extends DatabaseDriver {
      val dbname = "sqlite"
      def connect(uri: String) = {
        println("Connect to SQlite database: " + uri)
      }
    
      def createDriver() = new DbSqlite()
    }
    
    
    class DbPostgres extends DatabaseDriver {
      val dbname = "postgres"
      def connect(uri: String) = {
        println("Connect to Postgres database: " + uri)
      }
    
      def createDriver() = new DbPostgres()
    }
    
    
    
    class DbMysql extends DatabaseDriver {
      val dbname = "mysql"
      def connect(uri: String) = {
        println("Connect to Mysql database: " + uri)
      }
    
      def createDriver() = new DbMysql()
    }
    
    
    class DabaseFactory {
      val dbMap: scala.collection.mutable.Map[String, DatabaseDriver] = scala.collection.mutable.Map()
    
      def register(driver: DatabaseDriver) = {
        dbMap += (driver.dbname -> driver)
      }
    
      def getDatabase(dbname: String) = dbMap(dbname).createDriver()
    }
    
    
    val dbFactory = new DabaseFactory()
    
    /// Register database classe.
    dbFactory.register(new DbMysql())
    dbFactory.register(new DbSqlite())
    dbFactory.register(new DbPostgres())
    
    
    
    
    scala> val sqliteDriver = dbFactory.getDatabase("sqlite")
    sqliteDriver: DatabaseDriver = DbSqlite@41a9920d
    
    scala> val pgsqlDriver = dbFactory.getDatabase("postgres")
    pgsqlDriver: DatabaseDriver = DbPostgres@1a4b27e1
    
    scala> val mysqlDriver = dbFactory.getDatabase("mysql")
    mysqlDriver: DatabaseDriver = DbMysql@4f5a3111
    
    scala> 
    
    scala> sqliteDriver.dbname
    res61: String = sqlite
    
    scala> sqliteDriver.connect("file://somedb.sqlite")
    Connect to SQlite database: file://somedb.sqlite
    
    scala>
    

    Reference:

    1.17.2.4 Static Factory Method

    The static factory method is a design pattern that uses private constructor and static methods to create instances of the class, instead of public constructors and constructor overload. The benefits of this methods are:

    • Unlike constructors, static methods can have meaningful names.
    • It allows the private constructor to be changed without breaking client code.
    • Multiple constructors cannot have have different type signature. Static methods, doesn't have those limitations.
    • Allows multiple ways to instantiate a class.

    Note: It should not be confused with GOF's factory design pattern.

    Example 1:

    The class Interval uses milliseconds as its internal data representation and can be instantiated as an interval of seconds, minutes, hours or days.

    As Scala doesn't have static methods, this pattern is implemented using an companion-object which is a singleton with the same name of the class. The companion-object Interval can access any private method, field or constructor of the class Interval.

    // Constructor is private and it is only accessible from 
    // companion object
    class Interval private (timeMs: Double){  
      def getSeconds()  = timeMs / 1000.0 
      def getMinutes()  = timeMs / 60000.0
      def getHours()    = timeMs / 3600000.0
      def getDays()     = timeMs / 86400000.0
    }
    
    // The companion-object can access the class'
    // with same name private methods and data.
    //
    object Interval{
      def ofSeconds(time: Int) =
        new Interval(time * 1000)
    
      def ofMinutes(time: Int) =
        new Interval(time * 60000)
    
      def ofHours(time: Int) =
        new Interval(time * 3600000)
    
      def ofDays(time: Int) =
        new Interval(time *  86400000)
    }
    

    Testing in the REPL:

    scala> val i0 = new Interval(1000)
    <console>:13: error: constructor Interval in class Interval cannot be accessed in object $iw
           val i0 = new Interval(1000)
                    ^
    scala> val i1 = Interval.ofSeconds(600)
    i1: Interval = Interval@1da074ef
    
    scala> i1.getSeconds()
    res10: Double = 600.0
    
    scala> i1.getMinutes()
    res11: Double = 10.0
    
    scala> i1.getHours()
    res12: Double = 0.16666666666666666
    
    
    scala> val i2 = Interval.ofHours(3)
    i2: Interval = Interval@23d5ada9
    
    scala> i2.getSeconds()
    res13: Double = 10800.0
    
    scala> i2.getMinutes()
    res14: Double = 180.0
    
    scala> i2.getHours()
    res15: Double = 3.0
    
    scala> i2.getDays()
    res16: Double = 0.125
    

    Example 2:

    class Coordinate private (x: Double, y: Double) {
      import Math.{sqrt, atan2, PI}
      def getX() = x
      def getY() = y
      def getRadius() = sqrt(x * x + y * y)
      def getAngle()  = atan2(y, x) * 180.0 / PI
      // Get rectangular coordinates representation
      def getRec() = (x, y)
      // Get polar coordinates representation
      def getPol() = (getRadius(), getAngle())
    }
    
    object Coordinate{
      import Math.{sqrt, atan2, PI, sin, cos}
    
      // Default "constructor"
      def apply(x: Double, y: Double) =
        new Coordinate(x, y)
    
      // Create a coordinate in rectangular coordinate
      def ofRec(x: Double, y: Double) =
        new Coordinate(x, y)
    
       // Create a coordinate in polar coordinates
      def ofPol(radius: Double, angle: Double) = {
        // Angle "a" in Radians 
        val a = angle / 180.0 * PI
        new Coordinate(radius * cos(a), radius * sin(a))
      }
    }
    

    Repl test:

    scala> val c1 = new Coordinate(3.0, 5.0)
    <console>:13: error: constructor Coordinate in class Coordinate cannot be accessed in object $iw
           val c1 = new Coordinate(3.0, 5.0)
                    ^
    // Apply method 
    scala> val c1 = Coordinate(3.0, 5.0)
    c1: Coordinate = Coordinate@a9f946f
    
    scala> val c1 = Coordinate(5.0, 5.0)
    c1: Coordinate = Coordinate@2b86d46b
    
    scala> val c1 = Coordinate(0.0, 5.0)
    c1: Coordinate = Coordinate@de96d10
    
    scala> c1.getX()
    res19: Double = 0.0
    
    scala> c1.getY()
    res20: Double = 5.0
    
    scala> c1.getPol()
    res21: (Double, Double) = (5.0,90.0)
    
    
    scala> val c2 = Coordinate.apply(0.0, 5.0)
    c2: Coordinate = Coordinate@17d2221f
    
    scala> c2.getRec()
    res23: (Double, Double) = (0.0,5.0)
    
    scala> c2.getPol()
    res24: (Double, Double) = (5.0,90.0)
    
    
    // Create coordinate given in Polar Coordinates 
    scala> val c3 = Coordinate.ofPol(10.0, 45.0)
    c3: Coordinate = Coordinate@1f53e98
    
    scala> c3.getRec()
    res25: (Double, Double) = (7.0710678118654755,7.071067811865475)
    
    scala> c2.getPol()
    res27: (Double, Double) = (5.0,90.0)
    

    Futher Reading:

    1.17.3 Behavioral Patterns

    1.17.3.1 Strategy Pattern
    1. Overview

      Strategy pattern allows changing the algorithm (strategy) at run-time. The strategy object encapsulates the algorithm, in other words, implements the strategy to be executed. The context object switches its behavior by switching the context object.

      Intent: Define a family of algorithms, encapsulate each one, and make them interchangeable.

      This pattern has three main parts:

      • Strategy: the interface that defines how the algorithm will be called.
      • Concrete Strategy: the implementation of the strategy (algorithm).
      • Context: the object holding the Concrete Strategy.

      References:

    2. Example in OO way
      /// Interface for the Strategy - Algorithm
      trait Operation {
        def run(x: Double, y: Double): Double
      }
      
      /// -------- Concrete strategies ------- ///
      
      class AddOp() extends Operation {
        def run(x: Double, y: Double) = x + y
      }
      
      
      class SubOp extends Operation {
        def run(x: Double, y: Double) = x - y
      }
      
      class MulOp extends Operation {
        def run(x: Double, y: Double) = x * y
      }
      
      //----- Context - Class that selects the concrete strategy -- //
      
      class Context{
        private var strategy: Operation = null
      
        def setStrategy(strategyS: Operation) = {
          strategy = strategyS
        }
      
        def runStrategy(x: Double, y: Double) = {
          strategy.run(x, y)
        }
      
      }
      
      
      // ------- Running -------------- //
      
      scala> val ctx = new Context()
      ctx: Context = Context@2f18e88b
      
      scala> ctx.setStrategy(new AddOp())
      
      scala> ctx.runStrategy(10.0, 5.0)
      res69: Double = 15.0
      
      scala> ctx.setStrategy(new MulOp())
      
      scala> ctx.runStrategy(63.0, 4.0)
      res71: Double = 252.0
      
      scala> ctx.setStrategy(new SubOp())
      
      scala> ctx.runStrategy(63.0, 4.0)
      res73: Double = 59.0
      
      scala>
      
    3. Example in FP way

      In functional programming each algorithm is just a function. The context object can be replaced by a higher order function. By the changing the function argument of the context (higher order function) its changes the behavior.

      Variation 1: Each concrete strategy can become just a binary function.

      type Operation = (Double, Double) => Double
      
      val addOp: Operation = (x: Double, y: Double) => x + y
      val subOp: Operation = (x: Double, y: Double) => x - y
      val mulOp: Operation = (x: Double, y: Double) => x * y
      
      class Context{
        private var strategy: Operation = null
      
        def setStrategy(strategyS: Operation) = {
          strategy = strategyS
        }
      
        def runStrategy(x: Double, y: Double) = {
          strategy(x, y)
        }
      }
      
      
      scala> val ctx = new Context()
      ctx: Context = Context@26275bef
      
      scala> ctx.setStrategy(addOp)
      
      scala> ctx.runStrategy(10, 5)
      res1: Double = 15.0
      
      scala> ctx.setStrategy(mulOp)
      
      scala> ctx.runStrategy(10, 5)
      res3: Double = 50.0
      
      scala> ctx.setStrategy(subOp)
      
      scala> ctx.runStrategy(10, 5)
      res5: Double = 5.0
      
      scala>
      

      Variation 2: Only with functions:

      • The function runStrategy switches algorithms at run-time. The algorithm is just a function passed as argument.
      type Operation = (Double, Double) => Double
      
      val addOp: Operation = (x: Double, y: Double) => x + y
      val subOp: Operation = (x: Double, y: Double) => x - y
      val mulOp: Operation = (x: Double, y: Double) => x * y
      
      def runStrategy(strategy: Operation) =  (x: Double, y: Double) => strategy(x, y)
      
      
      scala> def runStrategy(strategy: Operation) =  (x: Double, y: Double) => strategy(x, y)
      runStrategy: (strategy: Operation)(Double, Double) => Double
      
      scala> runStrategy _
      res80: Operation => ((Double, Double) => Double) = <function1>
      
      scala> runStrategy(addOp)
      res75: (Double, Double) => Double = <function2>
      
      scala> runStrategy(addOp)(3, 4)
      res76: Double = 7.0
      
      scala> runStrategy(mulOp)(5, 10)
      res77: Double = 50.0
      
      scala> runStrategy(subOp)(5, 10)
      res78: Double = -5.0
      

      Variation 3: An alternative way to avoid defining many classes and using an mixed OOP and FP approach is to create a function that returns an anonymous class implementing the interface/trait operation. This method is useful when it is not possible to modify the code of the Operation trait/interface and class Context. This approach is also helpful in the case that many external codes, libraries and programs could be disrupted if the mentioned codes are modified.

      /// Interface for the Strategy - Algorithm
      trait Operation {
        def run(x: Double, y: Double): Double
      }
      
      //----- Context - Class that selects the concrete strategy -- //
      
      class Context{
        private var strategy: Operation = null
      
        def setStrategy(strategyS: Operation) = {
          strategy = strategyS
        }
      
        def runStrategy(x: Double, y: Double) = {
          strategy.run(x, y)
        }
      }
      
      // Converts a function to the interface "Operation"
      def makeStrategy(operation: (Double, Double) => Double) =
        new Operation{
          def run(x: Double, y: Double) = operation(x, y)
        }
      
      scala> val addOp = makeStrategy{(x, y) => x + y}
      addOp: Operation = $anon$1@6f0a4e30
      
      scala> val subOp = makeStrategy{(x, y) => x - y}
      subOp: Operation = $anon$1@5e020dd1
      
      scala> val mulOp = makeStrategy{(x, y) => x * y}
      mulOp: Operation = $anon$1@2a0ce342
      
      scala> val ctx = new Context()
      ctx: Context = Context@1e160a9e
      
      // Algorithm changed at run-time
      scala> ctx.setStrategy(addOp)
      
      scala> ctx.runStrategy(3.5, 4.5)
      res1: Double = 8.0
      
      scala> ctx.setStrategy(mulOp)
      
      scala> ctx.runStrategy(10, 3.5)
      res3: Double = 35.0
      

      Alternative 4: Languages like C++ and C# don't support anonymous classes like Java and Scala, so an alternative approach in this case is to create a classe implemeting the interface Operation that takes a lambda function as constructor argument and delegates the execution of the method defined in the interface to the lambda.

      /// Interface for the Strategy - Algorithm
      trait Operation {
        def run(x: Double, y: Double): Double
      }
      
      //----- Context - Class that selects the concrete strategy -- //
      
      class Context{
        private var strategy: Operation = null
      
        def setStrategy(strategyS: Operation) = {
          strategy = strategyS
        }
      
        def runStrategy(x: Double, y: Double) = {
          strategy.run(x, y)
        }
      }
      
      class FunctionToStrategy(operation: (Double, Double) => Double) extends Operation {
        def run(x: Double, y: Double) = operation(x, y)
      }
      
      scala> val addOp = new FunctionToStrategy((x, y) => x + y)
      addOp: FunctionToStrategy = FunctionToStrategy@43874120
      
      scala> val subOp = new FunctionToStrategy((x, y) => x - y)
      subOp: FunctionToStrategy = FunctionToStrategy@282506e1
      
      scala> val mulOp = new FunctionToStrategy((x, y) => x * y)
      mulOpt: FunctionToStrategy = FunctionToStrategy@7dbcbc7b
      
      
      scala> val ctx = new Context()
      ctx: Context = Context@7f53c24c
      
      // Algorithm changed at run-time
      scala> ctx.setStrategy(addOp)
      
      scala> ctx.runStrategy(3.5, 4.5)
      res1: Double = 8.0
      
      scala> ctx.setStrategy(mulOp)
      
      scala> ctx.runStrategy(10, 3.5)
      res3: Double = 35.0
      

      The alternative 4 could be also implemented in C++11:

      • File: strategyPattern.cpp
      #include <iostream>
      #include <functional>
      
      using std::string;
      using std::function;
      
      // Type synonym to function
      // type FOperation = (double, double) => double 
      using FOperation = function<double (double, double)>;
      
      // Class with only with pure virtual methods is equivalent to an interface.
      class IOperation{
      public:
          virtual string getName() = 0;
          virtual double run(double x, double y) = 0;
      };
      
      class Context{
      private:
          IOperation* _strategy = nullptr;
      
      public:
      
          void setStrategy(IOperation* strategy){
              _strategy = strategy;
          }
      
          double runStrategy(double x, double y){
              double result = _strategy->run(x, y);
              std::cout << "Running strategy = "
                        << _strategy->getName()
                        << "( x = " << x
                        << ", y = " << y
                        << ") = " << result
                        << std::endl;
              return _strategy->run(x, y);
          }       
      };
      
      // Turns a lambda function into a "Strategy" object
      class FunctionToStrategy: public IOperation{
      private:
          string     _name;
          FOperation  _oper;
      public: 
          FunctionToStrategy(string name, FOperation oper): _name(name), _oper(oper){}    
          string getName(){
              return _name;
          }
          double run(double x, double y){
              return _oper(x, y);
          }
      };
      
      int main(int argc, char** argv, char **environ){
          std::cout << "Testing mixed FP and OOP strategy pattern in C++" << std::endl;
      
          FunctionToStrategy strategyAdd = FunctionToStrategy(
              "add",
              [](double x, double y){ return x + y; }
              );
      
          FunctionToStrategy strategyMul = FunctionToStrategy(
              "mul",
              [](double x, double y){ return x * y; }
              );
      
          Context ctx;
      
          std::cout << std::endl;
          std::cout << "Testing operation add" << std::endl;
          std::cout << "---------------------" << std::endl;
          ctx.setStrategy(&strategyAdd);  
          double res0 = ctx.runStrategy(10.0, 20.0);
          std::cout << "Add result = " << res0 << std::endl;
          ctx.runStrategy(15.0, 20.0);
      
          std::cout << std::endl;
          std::cout << "Testing operation mul" << std::endl;
          std::cout << "---------------------" << std::endl;
          ctx.setStrategy(&strategyMul);
          double res1 = ctx.runStrategy(10.0, 20.0);
          std::cout << "Mul result = " << res1  << std::endl; 
          ctx.runStrategy(3, 5);
      
          // return zero status code
          return EXIT_SUCCESS;
      }
      

      Compiling and Running:

      $ clang++ strategyPattern.cpp -std=c++11 -o strategyPattern.bin && ./strategyPattern.bin 
      Testing mixed FP and OOP strategy pattern in C++
      
      Testing operation add
      ---------------------
      Running strategy = add( x = 10, y = 20) = 30
      Add result = 30
      Running strategy = add( x = 15, y = 20) = 35
      
      Testing operation mul
      ---------------------
      Running strategy = mul( x = 10, y = 20) = 200
      Mul result = 200
      Running strategy = mul( x = 3, y = 5) = 15
      
    1.17.3.2 Template Method

    The templated method design patterns is a behavioral design pattern which provides an algorithm, also known as template which defines some steps and defers the implementation of some steps to subclasses.

    It is stated by GOF as: "Defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithms structure."

    • Intent: Create an algorithm template that allows redefine some steps without changing its structure.

    The parent abstract class has four different types of methods:

    • Concrete methods: Methods implemented in the abstract class.
    • Abstract methods: Methods without implementation that must be implemented by subclasses.
    • Hook methods: Methods with default implementation that can be overriden by subclasses.
    • Template methods: Method that calls concrete methods, abstract methods or hook methods.

    Example: The method setepFn is a hook method with default implementation and the summation is a template method.

    trait IntervalSummation {
    
      // Summation method with default implementation
      def stepFn(a: Int) = a 
    
      // Summation of all numbers in the interval 
      def summation(lower: Int, upper: Int) = {
        var result = 0 
        for (a <- lower to upper) {
          result = result + stepFn(a)
        }
    
        result
      }
    }
    
    
    scala> class IntervalIdentity extends  IntervalSummation
    defined class IntervalIdentity
    
    scala> val intervId = new IntervalIdentity()
    intervId: IntervalIdentity = IntervalIdentity@59ede173
    
    scala> intervId.summation(0, 10)
    res14: Int = 55
    
    scala> intervId.summation(0, 100)
    res15: Int = 5050
    
    
    
    class IntervalSquare extends  IntervalSummation {
      override def stepFn(a: Int) = a * a
    }
    
    scala> intervSquare.summation(0, 10)
    res16: Int = 385
    
    scala> intervSquare.summation(0, 100)
    res17: Int = 338350
    
    
    class IntervalCube extends  IntervalSummation {
      override def stepFn(a: Int) = a * a * a 
    }
    
    
    scala> intervCube.summation(0, 10)
    res18: Int = 3025
    
    scala> intervCube.summation(0, 100)
    res19: Int = 25502500
    

    References:

    1.17.3.3 Iterator Pattern
    1. Overview

      The iterator pattern allows tranversing a collection or container without expose its internal structure and provides a uniform interface interface to tranverse different types of collections.

      • Stated by GOF as "Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation."

      Intent: Provide a way to transverse a collection or container sequentially not exposing its internal representation.

      Also known as:

      • Cursor

      Iterator Pattern Structure:

      • Iterfaces:
        • Collection
          • Methods:
            • createIterator() -> Creates a new iterator object specific for the underlying collection.
        • Iterator
          • Methods:
            • hasNext(): Bool -> Returns true if iterator has next element.
            • next() -> Get next element and advance to next element.
            • current() -> Get current element. (Optional)
            • remove() -> (Optional)

      Known uses:

      • This pattern is widely in Java, C# (.NET) and C++ STL containers.
      • Java
        • java.util.Iterator Interface
        • java.util.Enumerator interface
      • .NET
        • IEnumerable
        • IEnumerator

      Java iterator Interface:

      public interface java.util.Iterator<E> {
          boolean hasNext();
          E next();
          void remove();
      }
      

      References:

    2. Examples

      Example 1 - Java built-in iterator.

      scala> import java.util.Arrays
      import java.util.Arrays
      
      
      scala> val arr = Arrays.asList(1, 2, 3, 4, 5, 6, 7)
      arr: java.util.List[Int] = [1, 2, 3, 4, 5, 6, 7]
      
      scala> val iter = arr.iterator()
      iter: java.util.Iterator[Int] = java.util.AbstractList$Itr@3030836d
      
      scala> iter.hasNext _
      res2: () => Boolean = <function0>
      
      scala> iter.next _
      res3: () => Array[Int] = <function0>
      
      scala> iter.remove _
      res4: () => Unit = <function0>
      
      scala> iter.hasNext()
      res8: Boolean = true
      
      scala> iter.next()
      res9: Int = 1
      
      scala> iter.hasNext()
      res10: Boolean = true
      
      scala> iter.next()
      res11: Int = 2
      
      scala> iter.next()
      res12: Int = 3
      
      scala> iter.next()
      res13: Int = 4
      
      scala> iter.next()
      res14: Int = 5
      
      scala> iter.hasNext()
      res15: Boolean = true
      
      scala> iter.next()
      res16: Int = 6
      
      scala> iter.hasNext()
      res17: Boolean = true
      
      scala> iter.next()
      res18: Int = 7
      
      scala> iter.hasNext()
      res19: Boolean = false
      
      scala> iter.next()
      java.util.NoSuchElementException
        at java.util.AbstractList$Itr.next(AbstractList.java:364)
        ... 32 elided
      
      scala>
      

      Example 2 - Print all collection elements

      scala> import java.util.Arrays
      import java.util.Arrays
      
      scala> val arr = Arrays.asList(1, 2, 3, 4, 5, 6, 7)
      arr: java.util.List[Int] = [1, 2, 3, 4, 5, 6, 7]
      
      scala> val iter = arr.iterator()
      iter: java.util.Iterator[Int] = java.util.AbstractList$Itr@210d3a42
      
      while (iter.hasNext()) {
        println(iter.next())
      }
      
      scala> while (iter.hasNext()) {
           |   println(iter.next())
           | }
      1
      2
      3
      4
      5
      6
      7
      

      Example 3: Implementation a range iterator with java.util.iterator interface.

      class RangeIterator(from: Double, to: Double, step: Double) extends java.util.Iterator[Double] {
        private var cursor = from
      
        def hasNext() = cursor < to
      
        def next() = {
          if (!hasNext())
            error("Error: End of iteration, no more elements available.")
          else
          { val ret = cursor
            cursor = cursor + step
            ret
          }
        }
      
        def remove() = error("Error: Method not implemented")
      
      }
      
      
      scala> val rng = new RangeIterator(0.0, 5.0, 1.0)
      rng: RangeIterator = RangeIterator@1a6df932
      
      scala> rng.next()
      res41: Double = 0.0
      
      scala> rng.hasNext()
      res42: Boolean = true
      
      scala> rng.next()
      res43: Double = 1.0
      
      scala> rng.hasNext()
      res44: Boolean = true
      
      scala> rng.next()
      res45: Double = 2.0
      
      scala> rng.hasNext()
      res46: Boolean = true
      
      scala> rng.next()
      res47: Double = 3.0
      
      scala> rng.next()
      res48: Double = 4.0
      
      scala> rng.hasNext()
      res49: Boolean = false
      
      scala> rng.next()
      java.lang.RuntimeException: Error: End of iteration, no more elements available.
        at scala.sys.package$.error(package.scala:27)
        at scala.Predef$.error(Predef.scala:144)
        at RangeIterator.next(<console>:19)
        ... 32 elided
      
      scala>
      
      
      
      val iter = new RangeIterator(0.0, 10.0, 1.0)
      
      while (iter.hasNext()) {
        println(iter.next())
      }
      
      scala> while (iter.hasNext()) {
           |   println(iter.next())
           | }
      0.0
      1.0
      2.0
      3.0
      4.0
      5.0
      6.0
      7.0
      8.0
      9.0
      

      Example 4: Creating an iterator to iterate over file lines.

      class ReadFileLinesIterator(file: String) extends Iterator[String] {
        private var buf          = new java.io.BufferedReader(new java.io.FileReader(file))
        private var line: String = ""
        private var status       = true
      
        init()
      
        def init() {
          line = buf.readLine()
          status = line != null
        }
      
        def hasNext() = status
      
        def next() = {
          if (hasNext())
            {
              val ret = line
              line = buf.readLine()
              status = line != null
              ret
            }
          else
            error("Error: End of iteration. No more elements available.")
        }
      
        def remove() = error("Error: invalid method for this iterator.")
      }
      
      
      
      scala> val lineIter = new ReadFileLinesIterator("/etc/lsb-release")
      lineIter: ReadFileLinesIterator = non-empty iterator
      
      scala> lineIter.hasNext()
      res78: Boolean = true
      
      scala> lineIter.next()
      res79: String = DISTRIB_ID=ManjaroLinux
      
      scala> lineIter.hasNext()
      res80: Boolean = true
      
      
      scala> lineIter.next()
      res81: String = DISTRIB_RELEASE=17.0.1
      
      scala> lineIter.hasNext()
      res82: Boolean = true
      
      scala> lineIter.next()
      res83: String = DISTRIB_CODENAME=Gellivara
      
      scala> lineIter.hasNext()
      res84: Boolean = true
      
      scala> lineIter.next()
      res85: String = DISTRIB_DESCRIPTION="Manjaro Linux"
      
      scala> lineIter.next()
      java.lang.RuntimeException: Error: End of iteration. No more elements available.
        at scala.sys.package$.error(package.scala:27)
        at scala.Predef$.error(Predef.scala:144)
        at ReadFileLinesIterator.next(<console>:35)
        ... 32 elided
      
      scala> lineIter.hasNext()
      res87: Boolean = false
      
      scala>
      
      val lineIter = new ReadFileLinesIterator("/etc/lsb-release")
      while(lineIter.hasNext()){
        println(lineIter.next())
      }
      
      
      scala> while(lineIter.hasNext()){
           |   println(lineIter.next())
           | }
      DISTRIB_ID=ManjaroLinux
      DISTRIB_RELEASE=17.0.1
      DISTRIB_CODENAME=Gellivara
      DISTRIB_DESCRIPTION="Manjaro Linux"
      
    1.17.3.4 Command Design Pattern
    1. Overview

      Intent from GOF: "Encapsulate a request as an object, thereby letting you parametrize clients with different requests, queue or log requests, and support undoable operations."

      • Also known as: Action or transaction pattern.
      • Encapsulate method invocations as objects called commands, which can be stored and executed later by one or multiple invoker object which don't know anything about the method invocation or about the operation being performed.
        • Features:
        • Encapsulates method-calls as commands.
        • Provide a common interface for method calls.

      Participants:

      • Receiver - Object whose methods will be invoked indirectly by the objects implementing the ICommand interface. This name "receiver" comes from Smalltalk and means the object which receives the message (method call).
      • Invoker(s) - (Could also be called Sender). One or more object that store the command objects and executes them later. The invoker must have no knowledge about how to perform the method call.
        • The invoker objects can be a list of commands to be run; a stack of commands; user interface elements such as buttons, menus and etc, where each element stores a command that performs a application invocation such as App.print(), App.hidePanel(panel1).
      • ICommand - Command interface - Interface encapsulating the request or method invocation.
      • Client - Client means any code using a particular code, api, interface or object, in this case any code using this code. The client's role is to create the concrete commands setting their requests (methods of receiver that they invoke) and store the commands in the invoker(s).

      Use cases:

      • Grapical User Interfaces: Input UI elements such as buttons, menus and key bindings could act as invokers storing a high level application command such as "save document", "print document", "exit application" and so on. This approach allows to a separate the user interface from the application by decoupling the UI element that executes the command from the logic performed by the command and also allows a single command to be executed by multiple UI elements. For instance, an action such as "save document" could be encapsulated as a command object bound to many UI sources such the key binding ctr-s, a save button and a save menu item, as a result, any changes in the user interface code would not break the main application code.
      • Allow redo/undo
      • Transactions
      • Replace switch statements

      Possible Variations

      • Single invoker
      • Multiple invokers
      • Single receiver
      • Multiple receivers

      References and further reading

    2. Example 1 - Canvas drawing application with animation

      In this example, a graphical 2D animation application has tree main parts, a canvas where 2D shapes can be drawn, a scheduler that can that allows to schedule drawing commands to be executed in a given time interval and a command interface which encapsulates request to the canvas.

      It is clear that, the canvas plays the role of the receiver and scheduler plays the role of the invoker. The client code role in this case is create the concrete commands and pass the to the scheduler in order to create 2D animations.

      OOP Approach

      /** Receiver object */
      class Canvas {
        def drawLine(x1: Int, y1: Int, x2: Int, y2: Int) = 
          println(s"Draw line from p1 = (x1: $x1, y1: $y1)  to p2 = (x2: $x2, y2: $y2)")
      
        def drawCircle(x: Int, y: Int, radius: Int) =
          println(s"Draw ellipse at (x = $x, y = $y) with radius = $radius")
      
        def drawSquare(x: Int, y: Int, size: Int) = {
          println(s"Draw square at center ($x, $y) with size = $size")
        }
      
        def clear() =
          println("Clear canvas")  
      }
      
      /** Command Interface */
      trait ICommand{ 
        def execute(): Unit
      }
      
      class Scheduler{
        import scala.collection.mutable.ListBuffer
        private val _cmdlist = ListBuffer[(Int, ICommand)]()
      
        // Delay in milliseconds 
        def addCommand(delayMs: Int, cmd: ICommand) = {
          _cmdlist.append((delayMs, cmd))
        }
      
        def clearCommands() = 
          _cmdlist.clear()  
      
        def playCommands() =
          for ((time, cmd) <- _cmdlist){
            Thread.sleep(time)
            cmd.execute()
          }
      }
      
      
      /* ============== Concrete commands ============== */
      class DrawLine(
        canvas: Canvas,
        x1: Int, y1: Int, x2: Int, y2: Int
       ) extends ICommand {
        def execute() =
          canvas.drawLine(x1, y1, x2, y2)  
      }
      
      // Possible to write arguments in many styles,
      // including this quasi-tabular style.
      class DrawCircle(
        canvas: Canvas,
        x:      Int,
        y:      Int,
        radius: Int
      ) extends ICommand {  
        def execute() =
          canvas.drawCircle(x, y, radius)
      }
      
      class DrawSquare(canvas: Canvas, x: Int, y: Int, size: Int) extends ICommand{
        def execute() =
          canvas.drawSquare(x, y, size)
      }
      
      /** =============== Client Code =============== */
      // Creates animation by setting the commands and scheduler
      // 
      val canvas = new Canvas()
      val invoker = new Scheduler()
      
      val drawCmd1 = new DrawLine(canvas, 2, 10, 5, 6);
      val drawCmd2 = new DrawCircle(canvas, 5, 6, 20);
      val drawCmd3 = new DrawSquare(canvas, 9, 8, 34);
      
      invoker.addCommand(1500, drawCmd1)  // Execute command 1 after 1.5 seconds 
      invoker.addCommand(1000, drawCmd2)  // Execute command 2 after 2 seconds 
      invoker.addCommand(2000, drawCmd3)  // Execute command 3 after 3 seconds 
      
      scala> invoker.playCommands()
      Draw line from p1 = (x1: 2, y1: 10)  to p2 = (x2: 5, y2: 6)
      Draw ellipse at (x = 5, y = 6) with radius = 20
      Draw square at center (9, 8) with size = 34
      

      FP Approach

      • The disadvantage of the OO code is that it is necessary to create a new class for every method of the receiver object what will result in many files and lots of boilerplate code.

      Approach 1: Replace the interface ICommand with a function:

      /** Receiver object */
      class Canvas {
        def drawLine(x1: Int, y1: Int, x2: Int, y2: Int) = 
          println(s"Draw line from p1 = (x1: $x1, y1: $y1)  to p2 = (x2: $x2, y2: $y2)")
      
        def drawCircle(x: Int, y: Int, radius: Int) =
          println(s"Draw ellipse at (x = $x, y = $y) with radius = $radius")
      
        def drawSquare(x: Int, y: Int, size: Int) = {
          println(s"Draw square at center ($x, $y) with size = $size")
        }
      
        def clear() =
          println("Clear canvas")  
      }
      
      object ICommandTypes{
        type ICommand = () => Unit
      }
      
      import ICommandTypes._
      
      class Scheduler{
      
        import scala.collection.mutable.ListBuffer
        private val _cmdlist = ListBuffer[(Int, ICommand)]()
      
        // Delay in milliseconds 
        def addCommand(delayMs: Int, cmd: ICommand) = {
          _cmdlist.append((delayMs, cmd))
        }
      
        def clearCommands() = 
          _cmdlist.clear()  
      
        def playCommands() =
          for ((time, cmd) <- _cmdlist){
            Thread.sleep(time)
            cmd()
          }
      }
      
      /** =============== Client Code =============== */
      // 
      // Creates animation by setting the commands and the scheduler
      //
      
      val canvas = new Canvas()
      val invoker = new Scheduler()
      invoker.addCommand(1500, () => canvas.drawLine(2, 10, 5, 6))
      invoker.addCommand(1000, () => canvas.drawCircle(5, 6, 20))
      invoker.addCommand(2000, () => canvas.drawSquare(9 ,8 , 34))
      
      scala> invoker.playCommands()
      Draw line from p1 = (x1: 2, y1: 10)  to p2 = (x2: 5, y2: 6)
      Draw ellipse at (x = 5, y = 6) with radius = 20
      Draw square at center (9, 8) with size = 34
      
      
      // ---> Or it could also be <----
      // 
      val canvas = new Canvas()
      val invoker = new Scheduler()
      val cmd1 = () => canvas.drawLine(2, 10, 5, 6)
      val cmd2 = () => canvas.drawCircle(5, 6, 20)
      val cmd3 = () => canvas.drawSquare(9 ,8 , 34)
      invoker.addCommand(1500, cmd1)
      invoker.addCommand(1000, cmd2)
      invoker.addCommand(2000, cmd3)
      
      scala> invoker.playCommands()
      Draw line from p1 = (x1: 2, y1: 10)  to p2 = (x2: 5, y2: 6)
      Draw ellipse at (x = 5, y = 6) with radius = 20
      Draw square at center (9, 8) with size = 34
      
      // ---> Or it could also be <----
      //
      def makeCmdDrawCircle(canvas: Canvas, x: Int, y: Int, radius: Int) =
        () => canvas.drawCircle(x, y, radius)
      
      scala> val drawCircleAtOrigin = makeCmdDrawCircle(canvas, 0, 0, 25)
      drawCircleAtOrigin: () => Unit
      
      scala> invoker.addCommand(4000, drawCircleAtOrigin)
      
    3. Example 2 - Graphical user interface with FP approach

      In this example, every GUI button works as an invoker and main application as a receiver. The command pattern here can decouple the application from the GUI.

      • Running: The sample code can be run directly from the REPL with :paste and pasting the source code or loading the file with :paste src/commandGUIPattern.scala.
      scala> :paste src/commandGUIPattern.scala
      
      // User clicks at buttons or menu items. 
      scala> Save document to file file1.txt
      Save document to file file1.txt
      Save document to file file1.txt
      Open file = /data/fileTest.csv
      Open file = /data/fileTest.csv
      Fake command. DO NOT EXIT during test.
      Fake command. DO NOT EXIT during test.
      Fake command. DO NOT EXIT during test.
      
      // Run command directly 
      scala> cmdSave.execute()
      Save document to file file1.txt
      
      scala> cmdOpen.execute()
      Open file = /data/fileTest.csv
      
      • Screenshot:

      commandGUIPattern.png

      import javax.swing.{JFrame, JButton, JMenuItem, JMenuBar, JMenu}
      import java.awt.event.{ActionListener, ActionEvent}
      
      class Application{
        def saveDocument(file: String, data: String) =
          println(s"Save document to file $file")
      
        def openFile(file: String) = 
          println(s"Open file = $file")
      
        def printDocument() =
          println("Printing document ...")
      
        def exit() = {
          println("Shutdown systems ...")
          System.exit(0)
        }
      }
      
      trait ICommand extends ActionListener{
        // Abstract method 
        def execute(): Unit
      
        // Concrete method 
        def actionPerformed(evt: ActionEvent) =
          execute()
      }
      
      class MainGUI extends JFrame{
        private val btSave    = new JButton("Save")
        private val btOpen    = new JButton("Open")
        private val btClose   = new JButton("Close")
        private val menuSave  = new JMenuItem("Save")
        private val menuOpen  = new JMenuItem("Open")
        private val menuClose = new JMenuItem("Close")
      
        init()
        def init(){
          setLayout(new java.awt.FlowLayout())
          setTitle("FP - Command Design Pattern for GUIs")
          // Can be without this, but explicit is better than implicit!
          // this.settSize(300, 276)
          setSize(300, 276)   
          // Add buttons
          //==============
          this.add(btSave)
          this.add(btOpen)
          this.add(btClose)
          // Add menu bar
          //================
          val menu = new JMenu("Save")
          menu.add(menuOpen)        
          menu.add(menuSave)
          menu.add(menuClose)
          val menuBar = new JMenuBar()
          menuBar.add(menu)
          setJMenuBar(menuBar)
        }
      
        def setSaveCommand(cmd: ICommand) = {
          btSave.addActionListener(cmd)
          menuSave.addActionListener(cmd)
          this // return this for method chaining
        }
      
        def setOpenCommand(cmd: ICommand) = { 
          btOpen.addActionListener(cmd)
          menuOpen.addActionListener(cmd)
          this
        }
      
        def setExitCommand(cmd: ICommand) = { 
          btClose.addActionListener(cmd)
          menuClose.addActionListener(cmd)
          this
        }
      } //--- End of class MainGUI ---- // 
      
      
      
      // Approach 1: The function generates anonymous 
      // classes implementing the interface.
      //
      def makeCommand(action: => Unit) =
        new ICommand{
          def execute() = action
        }
      
      def makeOpenComand(app: Application, file: String) =
        new ICommand{
          def execute() = app.openFile(file)
        }
      
      val app = new Application()
      val gui = new MainGUI()
      gui.setVisible(true)
      val cmdSave = makeCommand{ app.saveDocument("file1.txt", "some data") }
      val cmdOpen = makeOpenComand(app, "/data/fileTest.csv")
      val cmdExit = makeCommand{ println("Fake command. DO NOT EXIT during test.")}
      gui.setSaveCommand(cmdSave)
      gui.setOpenCommand(cmdOpen)
      gui.setExitCommand(cmdExit)
      
    1.17.3.5 Observer / Publisher Subscriber
    1. Overview

      The observer pattern is stated by GOF as "Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically."

      The observer pattern is behavioral pattern defining a one-to-many dependency between subject and observer. The observers objects are notified about the subject changes.

      This pattern is widely used by GUIs toolkits, including Java Swing and spreadsheets. It is also a key part of MVC - Model View Controller.

      It is also known as:

      • Puhlisher/ Subscriber
      • Observable/ Observer
      • Subject / Observer

      Known uses in Frameworks:

      • Java: java.util.Observable
      • .NET: System.IObservable and System.IObserver

      Participants:

      • Subject - The subject object maintains references to all subscribed observers and notifies them when an event happens or its state changes.
        • Methods:
          • attach or subscribe - Attach observer.
          • detach/ unsubscribe or remove - Remove observer.
          • notify - Notify all observers,
      • Observer - Each Observer object has an update or notify method that is called by the subscribed subject when its states changes.
        • Methods:
          • update / notify - Notify or update observer.

      Mechanisms to send data to observers:

      • Pull model. Observer executes Subject.getData() to get data from subject.
      • Push model. The subject pass its data as argument of observers' update method. for o in observers do o.update(subject.data)

      References:

    2. Example in OO way

      Example: A temperature sensor publishes its temperature to 4 observers that displays the temperature in Celsius, Kelvin and Fahrenheit. It has also a GUI observer (View) that displays the temperature in Celsius. All observers(displays, aka views) are updated when the temperature changes.

      // Observer interface
      trait Observer[A] {
        def update(a: A)
      }
      
      // Subject interface
      trait Subject[A] {
        // Subscribe observer to subject updates
        def attach(obs: Observer[A]): Unit
      
        // Remove/ unsubscribe observer from subject updates
        def detach(obs: Observer[A]): Unit
      
        // Notify all observers
        def notifyObservers(a: A): Unit
      }
      
      // Concrete: Subject
      //----------------------------------
      //
      // Publishes temperature measurements.
      class TempSensor extends Subject[Double]{
        private var temp: Double = 0.0
        private var observers: Set[Observer[Double]] = Set()
      
        def attach(obs: Observer[Double]) =
          observers += obs
      
        def detach(obs: Observer[Double]) =
          observers -= obs
      
        def notifyObservers(tempNew: Double) = {
          temp = tempNew
          observers.foreach(_.update(tempNew))
          // for (obs <- observers) obs.update(tempNew)
        }
      
        def getTemp() = temp
      
      }
      
      
      // ---------- Concrete Observers ----------------- //
      
      class ConsoleCelsiusObserver extends Observer[Double]{
        def update(temp: Double) = {
          printf("Current temperature is %.3f in °C\n", temp)
        }
      } // End of class ConsoleCelsiusObserver
      
      class ConsoleKelvinObserver extends Observer[Double]{
        def update(temp: Double) = {
          printf("Current temperature is %.3f in °K\n", temp + 273.0)
        }
      } // End of class ConsoleKelvinObserver
      
      class ConsoleFahrenheitObserver(subject: Subject[Double]) extends Observer[Double]{
      
        init()
      
        def init() {
          subject.attach(this)
        }
      
        def update(temp: Double) = {
          val tempF = 5.0 / 9.0 * temp + 32.0
          printf("Current temperature is %.3f in F\n", tempF)
        }
      } // End of class ConsoleFahrenheitObserver
      
      
      /// Java Swing Observer
      class GuiCelsiusObserver(subject: Subject[Double]) extends Observer[Double] {
        private var frame   = new javax.swing.JFrame()
        private var display = new javax.swing.JLabel()
      
        init()
      
        def init(){
          frame.setSize(255, 71)
          frame.add(display)
          frame.show()
          frame.setTitle("Temperature View")
          subject.attach(this)
        }
      
        def update(temp: Double) = {
          display.setText("Temperature = %.3f C".format(temp))
        }
      }
      
      /// ----------- Classes Instantiation ---------- ///
      
      val sensor = new TempSensor()
      
      val consoleC = new ConsoleCelsiusObserver()
      sensor.attach(consoleC)
      
      val consoleK = new ConsoleKelvinObserver()
      sensor.attach(consoleK)
      
      val consoleF = new ConsoleFahrenheitObserver(sensor)
      
      val guiObs = new GuiCelsiusObserver(sensor)
      

      Running:

      scala> :paste src/observerPattern1.scala
      Pasting file src/observerPattern1.scala...
      warning: there was one deprecation warning; re-run with -deprecation for details
      
      ob_scala_eoldefined trait Observer
      defined trait Subject
      defined class TempSensor
      defined class ConsoleCelsiusObserver
      defined class ConsoleKelvinObserver
      defined class ConsoleFahrenheitObserver
      defined class GuiCelsiusObserver
      sensor: TempSensor = TempSensor@4dd02341
      consoleC: ConsoleCelsiusObserver = ConsoleCelsiusObserver@3212a8d7
      consoleK: ConsoleKelvinObserver = ConsoleKelvinObserver@7a1a3478
      consoleF: ConsoleFahrenheitObserver = ConsoleFahrenheitObserver@495b0487
      guiObs: GuiCelsiusObserver = GuiCelsiusObserver@55dfcc6
      
      // Manual simulation 
      //-------------------------------
      
      scala> sensor.notifyObservers(20.0)
      Current temperature is 20.000 in °C
      Current temperature is 293.000 in °K
      Current temperature is 43.111 in F
      
      scala> sensor.notifyObservers(20.1)
      Current temperature is 20.100 in °C
      Current temperature is 293.100 in °K
      Current temperature is 43.167 in F
      
      scala> sensor.notifyObservers(20.5)
      Current temperature is 20.500 in °C
      Current temperature is 293.500 in °K
      Current temperature is 43.389 in F
      
      scala> sensor.detach(consoleK)
      
      scala> sensor.notifyObservers(23.0)
      Current temperature is 23.000 in °C
      Current temperature is 44.778 in F
      
      // Automatic simulation
      //--------------------------------------
      
      def runTimer(interval: Int, taskFn: () => Unit) = {
        val task = new java.util.TimerTask() {
          def run() {
            taskFn()
          }
        }
      
        val timer = new java.util.Timer()
        // Run the task every 1 second interval (or 1000 milli seconds)
        timer.schedule(task, 1, interval)
        timer
      } // End of runTimer
      
      
      // Generates a random number within an interval
      // from (mid - delta) to (mid + delta)
      //
      def genRandomInterval(mid: Double, delta: Double) = {
        val rnd = new java.util.Random()
        () => { val x = rnd.nextDouble()
                2 * delta * x + (mid - delta) 
              }
      }
      
      scala> def genRandomInterval(mid: Double, delta: Double) = {
           |   val rnd = new java.util.Random()
           |   () => { val x = rnd.nextDouble()
           |           2 * delta * x + (mid - delta) 
           |         }
           | }
      genRandomInterval: (mid: Double, delta: Double)() => Double
      
      // Generates a temperature between 20.0 - 3.0 (17.0 C) and 20.0 + 3.0 (23 °C)
      scala> val genTemp = genRandomInterval(20.0, 3.0)
      genTemp: () => Double = <function0>
      
      
      // Update the temperature every 1 second 
      runTimer(1000, () => sensor.notifyObservers(genTemp()))
      
    3. Example in FP way

      As Scala is also a functional language, it allows functions be passed directly as argument, therefore the observer objects can be replaced by callbacks functions and the subject by some object with a mutable collection of callbacks.

      The subject or observable class was replaced by a record of stateful functions created with a closure, but it could remain as class as well.

      File: src/observerPatternFun.scala

      // Observer object is replace by a callback function 
      type Observer[A] = A => Unit
      
      // Record containing functions 
      case class Subject[A](
         attach: Observer[A] => Unit
        ,detach: Observer[A] => Unit
        ,notifyObservers: A  => Unit
        ,getState: () => A
      )
      
      def createSubject[A](stateInit: A) = {
        var observers : Set[A => Unit] = Set()  
        var state = stateInit
      
        val attach = (obs: Observer[A]) => {
          observers += obs 
        }
      
        val detach = (obs: Observer[A]) => {
          observers -= obs 
        }
      
        val notifyObservers = (a: A) => {
          state = a 
          for (obs <- observers) obs(a)
        }
      
        val getState = () => state
      
        Subject(attach, detach, notifyObservers, getState)
      }
      
      
      // The observer becomes just a function or callback!!
      def consoleCelsiusObserver(temp: Double) = {
        printf("Current temperature is %.3f in °C\n", temp)
      }
      
      def consoleKelvinObserver(temp: Double) = {
          printf("Current temperature is %.3f in °K\n", temp + 273.0)
      }
      
      def consoleFahrenheitObserver(temp: Double) = {
        val tempF = 5.0 / 9.0 * temp + 32.0
        printf("Current temperature is %.3f in F\n", tempF)
      }
      
      // Creates a function that updates the GUI display
      // 
      // Note: (Double => Unit) is optional.
      // The type annotation was added to make reading easier.
      //
      def makeGuiObserver(): (Double => Unit) = {
        val frame = new javax.swing.JFrame()
        val display = new javax.swing.JLabel()
        frame.setSize(255, 71)
        frame.add(display)
        frame.show()
        frame.setTitle("Temperature View")
        (temp: Double) =>  display.setText("Temperature = %.3f C".format(temp))
      }
      
      val sensor = createSubject[Double](20.0)
      sensor.attach(consoleCelsiusObserver)
      sensor.attach(consoleKelvinObserver)
      sensor.attach(consoleFahrenheitObserver)
      
      val guiObserver = makeGuiObserver()
      sensor.attach(guiObserver)
      

      Running:

      scala> :paste src/observerPatternFun.scala
      Pasting file src/observerPatternFun.scala...
      warning: there was one deprecation warning; re-run with -deprecation for details
      
      ob_scala_eoldefined type alias Observer
      defined class Subject
      createSubject: [A](stateInit: A)Subject[A]
      consoleCelsiusObserver: (temp: Double)Unit
      consoleKelvinObserver: (temp: Double)Unit
      consoleFahrenheitObserver: (temp: Double)Unit
      makeGuiObserver: ()Double => Unit
      sensor: Subject[Double] = Subject(<function1>,<function1>,<function1>,<function0>)
      guiObserver: Double => Unit = <function1>
      
      
      // Manual simulation
      //--------------------------------------
      
      scala>  sensor.notifyObservers(21.0)
      Current temperature is 21.000 in °C
      Current temperature is 294.000 in °K
      Current temperature is 43.667 in F
      
      scala>  sensor.notifyObservers(22.0)
      Current temperature is 22.000 in °C
      Current temperature is 295.000 in °K
      Current temperature is 44.222 in F
      
      scala>  sensor.notifyObservers(23.0)
      Current temperature is 23.000 in °C
      Current temperature is 296.000 in °K
      Current temperature is 44.778 in F
      
      scala>  sensor.notifyObservers(25.0)
      Current temperature is 25.000 in °C
      Current temperature is 298.000 in °K
      Current temperature is 45.889 in F
      
      
      // Automatic simulation
      //--------------------------------------
      
      
      def runTimer(interval: Int, taskFn: () => Unit) = {
        val task = new java.util.TimerTask() {
          def run() {
            taskFn()
          }
        }
      
        val timer = new java.util.Timer()
        // Run the task every 1 second interval (or 1000 milli seconds)
        timer.schedule(task, 1, interval)
        timer
      } // End of runTimer
      
      
      // Generates a random number within an interval
      // from (mid - delta) to (mid + delta)
      //
      def genRandomInterval(mid: Double, delta: Double) = {
        val rnd = new java.util.Random()
        () => { val x = rnd.nextDouble()
                2 * delta * x + (mid - delta) 
              }
      }
      
      
      scala> val genTemp = genRandomInterval(20.0, 3.0)
      genTemp: () => Double = <function0>
      
      scala> genTemp()
      res5: Double = 19.81265553013229
      
      scala> genTemp()
      res6: Double = 18.965575803660617
      
      scala> genTemp()
      res7: Double = 21.172101549312305
      
      scala> genTemp()
      res8: Double = 17.821626339663855
      
      scala> genTemp()
      res9: Double = 22.38493758505381
      
      
      // Update the temperature every 1 second 
      runTimer(1000, () => sensor.notifyObservers(genTemp()))
      
    4. Java built-in Observer Pattern

      Java provides the java.util.Observable and java.util.Observer interfaces to help implement the observer pattern.

      The subject/observable class inherits the Observable interface and notifies observer objects which implements the Observer interface.

      Example: Every time the temperature sensor gets a new temperature, the celsius and kelvin displays are updated with the temperature measurements.

      class TemperatureSensor(initTemp: Double) extends java.util.Observable {
        private var temp = initTemp
      
        def setValue(t: Double) {
          temp = t
          setChanged()
          notifyObservers()
        }
      
        def getValue() = temp 
      }
      
      
      // Observer that displays temperature in Celsius 
      class CelsiusObserver extends java.util.Observer {
        def update(obs: java.util.Observable, obj: Object){
          val ov = obs.asInstanceOf[TemperatureSensor]
          println("Temperature is = %.2f C".format(ov.getValue()))
        }
      }
      
      // Observer that displays temperature in Kelvin 
      class KelvinObserver extends java.util.Observer {
        def update(obs: java.util.Observable, obj: Object){
          val ov = obs.asInstanceOf[TemperatureSensor]
          val temp = ov.getValue() + 273.0 
          println("Temperature is = %.2f K".format(temp))
        }
      }
      
      val sensor = new TemperatureSensor(21.0)
      val celsiusObserver = new CelsiusObserver()
      val kelvinObserver  = new KelvinObserver()
      
      
      sensor.addObserver(celsiusObserver)
      sensor.addObserver(kelvinObserver)
      
      cala> sensor.getValue()
      res19: Double = 21.0
      
      scala> sensor.setValue(21.5)
      Temperature is = 294.50 K
      Temperature is = 21.50 C
      
      scala> sensor.setValue(21.6)
      Temperature is = 294.60 K
      Temperature is = 21.60 C
      
      scala> sensor.setValue(22)
      Temperature is = 295.00 K
      Temperature is = 22.00 C
      
      scala> 
      
      scala> sensor.countObservers()
      res23: Int = 2
      
      scala> sensor.deleteObserver(kelvinObserver)
      
      scala> sensor.setValue(23)
      Temperature is = 23.00 C
      
      
      scala> sensor.deleteObservers()
      
      scala> sensor.setValue(100)
      

      References:

    1.17.3.6 Model View Controller - MVC
    1. Overview

      The MVC - Model-View-Controller pattern was introduced by Trygve Reenskaug in a Smalltalk-80 implementation in 1970s to address the problem of building GUI - Graphical User Interfaces.

      The MVC has three parts:

      • View - The view is everything the user can see and it is resposible to render the model data. It is built with a hierarchy of widgets of some GUI toolkit such as Gtk, QT, Java Swing and etc.
        • Manages graphical or textual output.
      • Controller - The controller is a middleware between the view and model. The controller handles the user input or the events triggered by the view updating the model or the view.
        • Manages user input or GUI events such as button click, mouse move and etc.
      • Model - The model contains data to be displayed by the view and the business logic.
        • Manages application logic or domain logic.
        • The model must have no knowledge about the view or controller.
        • A model can have multiple views diplaying the model in different ways. Example bar chart, pie chart, table, spreadsheet display and so on. Each view must have an associated controller.
        • When the model is updated, it notifies all views that it has changed and the views query data from the model updating itself. The model is suitable to be implemented with observer pattern.
        • The MVC is supposed to have only one global model.

      mvc-model-view-controller-diagram.png

      MVC Variation:

      • Controller as mediator or MVP - Model View Presenter. The model doesn't interact directly with the view. It updates the view through the controller. This MVC variation is widely used in Apple's Cocoa framework.

      Benefits:

      • Separate the domain model from the presentation.
      • The same data can be displayed or rendered in many different ways. Multiple views for short.

      Drawbacks:

      • In a GUI it is hard to separate input from output, consequently it is hard to separate the view from the model. What makes them tightly coupled.

      References and Bookmarks:

      Apple's "MVC":

      Sample codes and examples:

      Java Swing:

      History:

    2. Example

      This example shows a simple GUI application with MVC and Java Swing toolkit using three views, one console view that prints the model state and two Java swing GUI views.

      File: src/mvcCounter.scala

      import javax.swing.{JFrame, JPanel, JTextField, JButton, JLabel}
      
      
      //-----------  Observer Pattern Interfaces ----------- //
      
      // Observer interface 
      trait Observer {
        def update(): Unit
      }
      
      // Subject or Observable interface 
      trait Observable {
      
        private var observers: Set[Observer] = Set()
      
        // Subscribe observer to subject updates 
        def attach(obs: Observer) {
          observers += obs 
        }
      
        // Remove/ unsubscribe observer from subject updates 
        def detach(obs: Observer) {
          observers -= obs 
        }
      
        // Notify all observers 
        def notifyObservers() {
          for (obs <- observers) obs.update() 
        }
      }
      
      
      //----------- Helpers to subscribe to events ------------- //
      
      /// Register callback function
      ///
      def onClick(button: JButton) (handler: () => Unit) = {
        button.addActionListener(
          new java.awt.event.ActionListener(){
            def actionPerformed(evt: java.awt.event.ActionEvent) = {
              handler()
            }
          }
        )
      }
      
      
      def onWindowExit(frame: javax.swing.JFrame) (handler: () => Unit) = {
        frame.addWindowListener(
          new java.awt.event.WindowAdapter(){
            override def windowClosing(evt: java.awt.event.WindowEvent) = {
              handler()
            }
        })
      }
      
      def showFrameSize(frame: javax.swing.JFrame){
        println(frame.getSize())
      }
      
      
      //--------------- MVC Counter Demo -------------------- // 
      
      
      class CounterModel(init: Int) extends Observable{
        private var counter = init
      
        def getValue() = counter
      
        def increment() = {
          counter = counter + 1   // Every time the model state is changed,
                                  // the observers must be notified.
      
          this.notifyObservers()  // the 'this' prefix is optional.
        }
      
        def decrement() = {
          counter = counter - 1
          this.notifyObservers()  
        } 
      }
      
      /// This view doesn't need a controller as this doesn't need an input.
      class ConsoleView(counter: CounterModel) extends Observer{
        init()
      
        def init(){
          // Register observer (this class)
          counter.attach(this)
        }
      
        // updates the view 
        def update() {
          println("Counter value is = " + counter.getValue())
        }
      }
      
      
      class GuiView1(counter: CounterModel) extends Observer{
        private val frame   = new JFrame("Counter MVC App")
        private val panel   = new JPanel(new java.awt.FlowLayout())
        private val label   = new JLabel("Counter")
        private val display = new JTextField(10)
        private val btnInc  = new JButton("Increment")
        private val btnDec  = new JButton("Decrement")
        private val btnExit = new JButton("Exit")
      
        init()
      
        def init(){
          // Register observer (this class)
          counter.attach(this)
      
          panel.add(label)
          panel.add(display)
          panel.add(btnInc)
          panel.add(btnDec)
          panel.add(btnExit)
      
          display.setEditable(false)
          frame.add(panel)
          frame.setSize(600, 100)
          frame.show()
      
          // Exit application if user closes window.
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
      
          this.update()
        }
      
        // updates the view 
        def update() {
          display.setText(counter.getValue().toString())
        }
      
        def onIncrement(handler: () => Unit) {
          onClick(btnInc)(handler)
        }
      
        def onDecrement(handler: () => Unit) {
          onClick(btnDec)(handler)
        }
      
        def onExit(handler: () => Unit) = {
          onClick(btnExit)(handler)
        }
      
        def show(){
          frame.show()
        }
      }
      
      class GuiView1Controller(viewp: GuiView1, modelp: CounterModel){
        private var view  = viewp
        private var model = modelp
        init()
      
        def init(){
      
          //---> Model Manipulation 
          view.onIncrement(this.increment)
          view.onDecrement(this.decrement)
      
          //---> GUI manipulation 
          view.onExit(() => System.exit(0))
        }
      
        def increment(){
          model.increment()
        }
      
        def decrement(){
          model.decrement()
        }
      
      }
      
      // View without input that only displays the model.
      // This view doesn't need a controller as it doesn't
      // have any user input.
      //
      class GuiView2(counter: CounterModel) extends Observer{
        private val frame   = new JFrame("Counter App - Display only view")
        private val panel   = new JPanel()
        private val display = new JLabel()
      
        init()
      
        def init(){
          counter.attach(this)
      
          panel.add(display)
          frame.setSize(354, 54)
          frame.add(panel)
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
          frame.show()
          update()
        }
      
        // Method required by Observer interface 
        def update(){
          display.setText(counter.getValue().toString())
          // showFrameSize(frame)
        }
      }
      
      
      val counterModel = new CounterModel(0)
      val consoleView  = new ConsoleView(counterModel)
      
      val guiView1           = new GuiView1(counterModel)
      val guiView1Controller = new GuiView1Controller(guiView1, counterModel)
      
      val guiView2           = new GuiView2(counterModel)
      

      Running:

      $ scala mvcCounter.scala 
      warning: there were three deprecation warnings; re-run with -deprecation for details
      one warning found
      Counter value is = 1
      Counter value is = 2
      Counter value is = 3
      Counter value is = 4
      ... ...
      

      counterMvcExample.png

    1.17.3.7 Model View Presenter with Passive View - MVP
    1. Overview

      The MVP - Model-View-Presenter is variation of MVC Model-View-Controller which the model doesn't communicate directly with the view and it is made passive. This pattern is often designated as MVC.

               View event triggered
               by user.
      
               +.....->>>-.......+            +........<<<<..........+
              /  (User action)    \          /   Model notification   \ 
             /                     \        /    event                 \   
          View                     Presenter                          Model
            \                      /       \                           /
             \   View update      /         \     Model update        /
              +----<<<-----------/           +--->>>------>>>--------+
      
      Legend: 
      
       ...... - Event or notification
       ------ - Method call or action.
      
      • Model
        • The model is responsible for the business logic or domain logic and application state.
        • As in the MVC, the model must have no knowledge about the view or presenter.
        • Unlike the MVC, the model must not communicate directly with the view, instead it must notify the presenter that it has changed. It can be done using the observer pattern with the model playing the role of observable or observer and the presenter acting as observer.
      • View
        • The view role is display the model.
        • Passive view:
          • The view must not have any knowledge about the model and not access it directly.
          • The view doesn't update itself from the model. It is updated by the presenter.
          • The view delegates use input events to the presenter.
      • Presenter
        • The presenter role is to handle the presentation logic and mediate the communication between the model and view updating the view with the model data and also handling view events and model notifications.
        • Presenter - View communication:
          • The presenter handles events received from the view and manipulates the view or the model.
        • Presenter - Model communication:
          • The presenter receives notifications from the model and updates the view with model data in suitable format to the view.

      References and Bookmarks:

    2. Example

      This example is similar to the MVC counter example.

      File: src/mvpCounter.scala

      import javax.swing.{JFrame, JPanel, JTextField, JButton, JLabel}
      
      
      //-----------  Observer Pattern Interfaces ----------- //
      
      // Observer interface 
      trait Observer {
        def update(): Unit
      }
      
      // Subject or Observable interface 
      trait Observable {
      
        private var observers: Set[Observer] = Set()
      
        // Subscribe observer to subject updates 
        def attach(obs: Observer) {
          observers += obs 
        }
      
        // Remove/ unsubscribe observer from subject updates 
        def detach(obs: Observer) {
          observers -= obs 
        }
      
        // Notify all observers 
        def notifyObservers() {
          for (obs <- observers) obs.update() 
        }
      }
      
      
      //----------- Helpers to subscribe to events ------------- //
      
      /// Register callback function
      ///
      def onClick(button: JButton) (handler: () => Unit) = {
        button.addActionListener(
          new java.awt.event.ActionListener(){
            def actionPerformed(evt: java.awt.event.ActionEvent) = {
              handler()
            }
          }
        )
      }
      
      
      def onWindowExit(frame: javax.swing.JFrame) (handler: () => Unit) = {
        frame.addWindowListener(
          new java.awt.event.WindowAdapter(){
            override def windowClosing(evt: java.awt.event.WindowEvent) = {
              handler()
            }
        })
      }
      
      
      //--------------- MVP Counter Demo -------------------- //
      
      
      
      class CounterModel(init: Int) extends Observable{
        private var counter = init
      
        def getValue() = counter
      
        def increment() = {
          counter = counter + 1   // Every time the model state is changed,
                                  // the observers must be notified.
      
          this.notifyObservers()  // the 'this' prefix is optional.
        }
      
        def decrement() = {
          counter = counter - 1
          this.notifyObservers()  
        } 
      }
      
      
      
      class CounterView extends {
        private val frame   = new JFrame("Counter MVC App")
        private val panel   = new JPanel(new java.awt.FlowLayout())
        private val label   = new JLabel("Counter")
        private val display = new JTextField(10)
        private val btnInc  = new JButton("Increment")
        private val btnDec  = new JButton("Decrement")
        private val btnExit = new JButton("Exit")
      
        init()
      
        def init(){
          panel.add(label)
          panel.add(display)
          panel.add(btnInc)
          panel.add(btnDec)
          panel.add(btnExit)
      
          display.setEditable(false)
          frame.add(panel)
          frame.setSize(600, 100)
          // Exit application if user closes window.
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)   
        }
      
        // updates the view 
        def setDisplay(value: String) {
          display.setText(value)
        }
      
        def onIncrement(handler: () => Unit) {
          onClick(btnInc)(handler)
        }
      
        def onDecrement(handler: () => Unit) {
          onClick(btnDec)(handler)
        }
      
        def onExit(handler: () => Unit) = {
          onClick(btnExit)(handler)
        }
      
        def show(){
          frame.show()
        }
      }
      
      
      
      class CounterPresenter(model: CounterModel) extends Observer{
        private val view  = new CounterView()
      
        init()
      
        def init(){
      
          // Subscribe presenter to model updates 
          model.attach(this)
      
          //---> Model Manipulation 
          view.onIncrement(this.increment)
          view.onDecrement(this.decrement)
      
          //---> GUI manipulation 
          view.onExit(() => System.exit(0))
      
          // Initial model display
          this.update()
        }
      
        def increment(){
          model.increment()
        }
      
        def decrement(){
          model.decrement()
        }
      
        // Method required by Observer interface. It updates the view
        // when the model notifies the presenter that its state has
        // changed.
        def update(){
          view.setDisplay(model.getValue().toString())
        }
      
        def show() = view.show()
      
      }
      
      
      val counterModel = new CounterModel(0)
      val presenter    = new CounterPresenter(counterModel)
      presenter.show()
      

    2 Bookmarks and Resources

    2.3 Java and Scala Libraries

    2.3.1 Scala Libraries

    Selection of third party Scala libraries.

    • Database
      • Slick
      • Squerly - "A Scala ORM and DSL for talking with Databases with minimum verbosity and maximum type safety".
    • Category Theory and Functional Programming
      • Cats - Provides abstractions for functional programming such as type clases, monads, monoids, functor and so on.
      • Scalaz - Extension of core Scala library for functional programming based on Haskell with many category theory abstractions such as functor, monad, monoid and etc.
    • Reactive Programming - (Event-driven programming)
      • RxScala - Reactive Extensions for Scala. Based on .NET
      • Rx.Scala - "An experimental library for Functional Reactive Programming in Scala"
    • Actor Model
      • Scala - Akka - Actor model library for Scala based on Erlan's Actor model implementation.
    • Testing
      • Spec2 - "Software specification for Scala"
      • ScalaCheck - Propery-based testing for Scala based on Haskell's QuickCheck.
    • RPC - Remote Procedure Call
      • Finagle - "Finagle is an extensible RPC system for the JVM, used to construct high-concurrency servers. Finagle implements uniform client and server APIs for several protocols, and is designed for high performance and concurrency. Most of Finagle’s code is protocol agnostic, simplifying the implementation of new protocols."
    • Web Framework - Libraries or Frameworks to build Web Sites, Web applications or Web Servers.
    • Math
      • Spire - "Powerful new number types and numeric abstractions for Scala." -

    See also:

    • Awesome Scala - "A community driven list of useful Scala libraries, frameworks and software. This is not a catalog of all the libraries, just a starting point for your explorations."

    2.3.2 Java Libraries

    Selection of useful Java third party libraries.

    See also:

    2.5 Reports

    Author: nobody

    Created: 2018-06-17 Sun 05:42

    Emacs 25.3.1 (Org mode 8.2.10)

    Validate