Scala Recipes

Table of Contents

  • Index
  • Repository
  • 1 Scala Recipes - Examples about integration with Java

    1.1 Show Java Properties

    scala>  System.getProperty ("java.vm.vendor")
    res2: String = Oracle Corporation
    
    scala>  System.getProperty ("java.home")
    res3: String = /usr/lib/jvm/java-8-openjdk/jre
    
    scala>  List("java.vm.vendor", "java.home", "java.runtime.name", "java.vm.name").map(System.getProperty)
    res4: List[String] = List(Oracle Corporation, /usr/lib/jvm/java-8-openjdk/jre, OpenJDK Runtime Environment, OpenJDK 64-Bit Server VM)
    
    scala>  val xs = List("java.vm.vendor", "java.home", "java.runtime.name", "java.vm.name")
    xs: List[String] = List(java.vm.vendor, java.home, java.runtime.name, java.vm.name)
    
    scala>  xs.foreach(p => println ("%s\t%s".format(p, System.getProperty(p))))
    java.vm.vendor  Oracle Corporation
    java.home   /usr/lib/jvm/java-8-openjdk/jre
    java.runtime.name   OpenJDK Runtime Environment
    java.vm.name    OpenJDK 64-Bit Server VM
    

    1.2 Java Reflection

    1.2.1 Show Class Method given a class name

    See: Reflection

    scala> Class.forName("java.io.File").getDeclaredMethods().take(10).foreach(println)
    public boolean java.io.File.equals(java.lang.Object)
    public java.lang.String java.io.File.toString()
    public int java.io.File.hashCode()
    public int java.io.File.compareTo(java.lang.Object)
    public int java.io.File.compareTo(java.io.File)
    public java.lang.String java.io.File.getName()
    public long java.io.File.length()
    public java.lang.String java.io.File.getParent()
    public boolean java.io.File.isAbsolute()
    public java.lang.String java.io.File.getCanonicalPath() throws java.io.IOException
    
    def show_class_methods (classname: String) {
      Class
        .forName(classname)
        .getDeclaredMethods()
        .foreach(println)
    }
    
    show_class_methods: (classname: String)Unit
    
    scala> show_class_constructors("javax.swing.JFrame")
    protected void javax.swing.JFrame.frameInit()
    protected javax.swing.JRootPane javax.swing.JFrame.createRootPane()
    protected void javax.swing.JFrame.processWindowEvent(java.awt.event.WindowEvent)
    public void javax.swing.JFrame.setDefaultCloseOperation(int)
    public int javax.swing.JFrame.getDefaultCloseOperation()
    public void javax.swing.JFrame.setTransferHandler(javax.swing.TransferHandler)
    public javax.swing.TransferHandler javax.swing.JFrame.getTransferHandler()
    public void javax.swing.JFrame.setJMenuBar(javax.swing.JMenuBar)
    public javax.swing.JMenuBar javax.swing.JFrame.getJMenuBar()
    ...
    
    def show_class_constructors (classname: String) {
      Class
        .forName(classname)
        .getDeclaredConstructors()
        .foreach(println)
    }
    
    scala> show_class_constructors("java.io.File")
    public java.io.File(java.lang.String,java.lang.String)
    public java.io.File(java.lang.String)
    private java.io.File(java.lang.String,java.io.File)
    public java.io.File(java.io.File,java.lang.String)
    public java.io.File(java.net.URI)
    private java.io.File(java.lang.String,int)
    
    scala> Class.forName("java.io.File").getDeclaredFields().foreach(println)
    private static final java.io.FileSystem java.io.File.fs
    private final java.lang.String java.io.File.path
    private transient java.io.File$PathStatus java.io.File.status
    private final transient int java.io.File.prefixLength
    public static final char java.io.File.separatorChar
    public static final java.lang.String java.io.File.separator
    public static final char java.io.File.pathSeparatorChar
    public static final java.lang.String java.io.File.pathSeparator
    private static final long java.io.File.PATH_OFFSET
    private static final long java.io.File.PREFIX_LENGTH_OFFSET
    private static final sun.misc.Unsafe java.io.File.UNSAFE
    private static final long java.io.File.serialVersionUID
    private transient volatile java.nio.file.Path java.io.File.filePath
    static final boolean java.io.File.$assertionsDisabled
    

    1.2.2 Show Object Methods

    def showObjectMethods(obj: Any) = {
        obj.getClass().getDeclaredMethods().foreach(println)
    }
    

    Test:

    scala> import scala.io.Source
    import scala.io.Source
    
    scala> import java.net.URL
    import java.net.URL
    
    scala> val url = new URL("http://www.httpbin.org/get")
    url: java.net.URL = http://www.httpbin.org/get
    
    
    scala> showObjectMethods(url)
    public boolean java.net.URL.equals(java.lang.Object)
    public java.lang.String java.net.URL.toString()
    public synchronized int java.net.URL.hashCode()
    public final java.io.InputStream java.net.URL.openStream() throws java.io.IOException
    private synchronized void java.net.URL.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundException
    private synchronized void java.net.URL.writeObject(java.io.ObjectOutputStream) throws java.io.IOException
    void java.net.URL.set(java.lang.String,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String)
    void java.net.URL.set(java.lang.String,java.lang.String,int,java.lang.String,java.lang.String)
    private java.lang.Object java.net.URL.readResolve() throws java.io.ObjectStreamException
    public java.lang.String java.net.URL.getPath()
    public java.net.URI java.net.URL.toURI() throws java.net.URISyntaxException
    public java.lang.String java.net.URL.getAuthority()
    public java.lang.String java.net.URL.getQuery()
    public java.net.URLConnection java.net.URL.openConnection(java.net.Proxy) throws java.io.IOException
    public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
    public java.lang.String java.net.URL.getProtocol()
    public java.lang.String java.net.URL.getFile()
    public java.lang.String java.net.URL.getHost()
    ...
    

    1.2.3 Show Object Public Methods

    import java.lang.reflect.Modifier
    
    def showObjPublicMethods (obj: Any) {
        for (m <- url.getClass().getDeclaredMethods()
                 if Modifier.isPublic(m.getModifiers)
             ) println(m)
    }
    

    Example:

    scala> import java.net.URL
    import java.net.URL
    
    
    scala> showObjPublicMethods(url)
    
    public boolean java.net.URL.equals(java.lang.Object)
    public java.lang.String java.net.URL.toString()
    public synchronized int java.net.URL.hashCode()
    public final java.io.InputStream java.net.URL.openStream() throws java.io.IOException
    public java.lang.String java.net.URL.getPath()
    public java.net.URI java.net.URL.toURI() throws java.net.URISyntaxException
    public java.lang.String java.net.URL.getAuthority()
    public java.lang.String java.net.URL.getQuery()
    public java.net.URLConnection java.net.URL.openConnection(java.net.Proxy) throws java.io.IOException
    public java.net.URLConnection java.net.URL.openConnection() throws java.io.IOException
    public java.lang.String java.net.URL.getProtocol()
    public java.lang.String java.net.URL.getFile()
    public java.lang.String java.net.URL.getHost()
    public java.lang.String java.net.URL.getUserInfo()
    public int java.net.URL.getPort()
    public int java.net.URL.getDefaultPort()
    public java.lang.String java.net.URL.getRef()
    public boolean java.net.URL.sameFile(java.net.URL)
    public java.lang.String java.net.URL.toExternalForm()
    public final java.lang.Object java.net.URL.getContent(java.lang.Class[]) throws java.io.IOException
    public final java.lang.Object java.net.URL.getContent() throws java.io.IOException
    public static void java.net.URL.setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory)
    

    1.2.4 Show Object's Public Method Names

    import java.lang.reflect.Modifier
    
    def showObjMethodNames (obj: Any){
      for (m <- obj.getClass().getDeclaredMethods()
           if Modifier.isPublic(m.getModifiers)
      ) println(m.getName())
    }
    

    Example:

    scala> showObjMethodNames(url)
    equals
    toString
    hashCode
    openStream
    getPath
    toURI
    getAuthority
    getQuery
    openConnection
    openConnection
    getProtocol
    getFile
    getHost
    ...
    

    1.3 GUI - Graphical User Interface (Java Swing)

    1.3.1 Messagebox

    def messageBox (title: String, content: String) {
      javax.swing.JOptionPane.showMessageDialog (
        null,
        content,
        title,
        javax.swing.JOptionPane.PLAIN_MESSAGE
      )
     }
    
    messageBox("Information", "Download of file animation.jar completed")
    

    messageBox1.png

    1.3.2 Password Dialog

    import javax.swing.{JFrame, JLabel, JButton, JPanel, JPasswordField}
    
    def getPassword(passwd: javax.swing.JPasswordField) =
      new String(passwd.getPassword())
    
    /// 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
          }
      })
    }
    
    val frame = new JFrame("Scala password entry")
    frame.setSize(400, 200)
    frame.setLayout(new java.awt.GridLayout(2, 1))
    
    // frame.setLayout()
    
    val panel  = new JPanel(new java.awt.FlowLayout())
    val label  = new JLabel("Password")
    val passwd = new JPasswordField(10)
    val btn    = new JButton("Login")
    val status = new JLabel("Safe closed")
    passwd.setEchoChar('*')
    
    
    panel.add(label)
    panel.add(passwd)
    panel.add(btn)
    
    
    frame.add(panel)
    frame.add(status)
    
    frame.setVisible(true)
    
    //--------- Event Handling ----------
    
    def checkPassword(
      passwd: String,
      input: String,
      okHanlder: () => Unit,
      errHandler: () => Unit ) = {
    
      if (input == passwd)
        okHanlder()
      else
        errHandler()
    }
    
    onClick(btn){ println("I was clicked")}
    
    onClick(btn) {
      val pass = getPassword(passwd)
      if (pass == "thepassword")
        println("Safe opened")
      else
        println("Error: Wrong password")
    }
    
    onClick(btn){
      checkPassword(
        "thepassword"
       ,getPassword(passwd)
       ,() => status.setText("Safe opened. Ok")
       ,() => status.setText("Error: Wrong password")
      )}
    
    onWindowExit(frame){ System.exit(0) }
    

    passwordGui1.png

    passwordGui2.png

    1.3.3 List View Dialog

    The function listView is useful for data vizualization of lists, files, numbers and son on.

    /// Function to visualize data in List View Mode
    ///
    def listView(elements: Array[String]){
      val frame  = new javax.swing.JFrame("List Data View")
      val model  = new javax.swing.DefaultListModel[String]()
      val list   = new javax.swing.JList(model)
      val scroll = new javax.swing.JScrollPane(list)
      frame.add(scroll)
      elements.foreach(model.addElement)
      frame.setSize(300, 400)
      frame.setVisible(true)
    }
    
    
    def listFiles(path: String) = {
      (new java.io.File(path))
        .listFiles()
        .map(_.toString)
    }
    

    Show the files of directory etc

    listView(listFiles("/etc"))
    

    listViewFiles.png

    Show java properties

    import scala.collection.JavaConverters._
    val properties = System.getProperties().asScala.toArray.map { case (k, v) => k + " = " + v }
    listView(properties)
    

    listViewJavaProperties.png

    1.3.4 Text View Dialog

    def textView(file: String) = {
      val frame = new javax.swing.JFrame("Text View App")
      val textArea = new javax.swing.JTextArea()
      val scroll = new javax.swing.JScrollPane(textArea)
      textArea.setText("")
      frame.add(scroll)
      frame.setSize(300, 400)
      frame.setVisible(true)
      val text = scala.io.Source.fromFile(file).mkString
      textArea.setText(text)
    }
    
    scala> textView("/etc/protocols")
    

    textView1.png

    1.3.5 Clock Display

    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
    }
    
    def currentTime() = {
      java.time.LocalDateTime.now.toString
    }
    
    
    val frame = new javax.swing.JFrame("Java Clock App")
    val label = new javax.swing.JLabel("")
    frame.add(label)
    frame.setSize(375, 76)
    frame.setVisible(true)
    
    
    runTimer(1000, () => label.setText(currentTime()))
    

    clockDisplayGui.png

    1.4 Http Get Request

    Java Code - https://www.mkyong.com/java/how-to-send-http-request-getpost-in-java/

    def httpGetRead(url: String) = {
      val obj = new java.net.URL(url)
      val conn = obj.openConnection().asInstanceOf[java.net.HttpURLConnection]
      conn.setRequestMethod("GET")
      conn.setRequestProperty("User-Agent", "Scala browser")
      val respCode = conn.getResponseCode()
    
      val bf = new java.io.BufferedReader(
        new java.io.InputStreamReader(conn.getInputStream()))
    
      val out = Stream.continually(bf.readLine())
        .takeWhile(_!=null)
        .mkString("\n")
      out
    }
    
    scala> httpGetRead("http://www.httpbin.org/get")
    res24: String =
    {
      "args": {},
      "headers": {
        "Accept": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2",
        "Connection": "close",
        "Host": "www.httpbin.org",
        "User-Agent": "Scala browser"
      },
      "origin": "186.212.135.2",
      "url": "http://www.httpbin.org/get"
    }
    

    1.5 Using a jar files or java library

    Example: Using JFreeChart chart library.

    1. Download JFreeChart
    $ mkdir ~/test && cd ~/test 
    $ mkdir lib
    
    # Download jars 
    $ curl -o lib/jfreechart.jar -L http://repo1.maven.org/maven2/org/jfree/jfreechart/1.0.19/jfreechart-1.0.19.jar
    $ curl -o lib/jcommon.jar -L http://repo1.maven.org/maven2/org/jfree/jcommon/1.0.23/jcommon-1.0.23.jar
    
    # Download this file to check dependencies
    $ curl -O http://repo1.maven.org/maven2/org/jfree/jfreechart/1.0.19/jfreechart-1.0.19.pom
    
    1. Start Scala REPL with:
    $ scala -cp lib/jcommon.jar:lib/jfreechart.jar
    

    or

    $ 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> :require lib/jcommon.jar
    Added '/home/archbox/test/lib/jcommon.jar' to classpath.
    
    scala> :require lib/jfreechart.jar
    Added '/home/archbox/test/lib/jfreechart.jar' to classpath.
    
    1. Plotting a pie chart. It was based on JFreeChart Tutorial.

    File: src/jfreeChart1.scala

    The lines below can be pasted in the Scala REPL and the user can and manipulate the chart objects and modify it interactively.

    import org.jfree.chart.{ChartPanel, ChartFactory, JFreeChart, ChartUtilities}
    import org.jfree.data.general.DefaultPieDataset
    
    val dataset = new DefaultPieDataset()
    
    dataset.setValue("A", 75)
    dataset.setValue("B", 10)
    dataset.setValue("C", 10)
    dataset.setValue("D", 5)
    
    val chart = ChartFactory.createPieChart(
      "Sample Pie Chart", // Title
      dataset,            // Dataset 
      true,               // Show legend
      true,               // Tooltips on
      false 
    )
    
    // Save chart to a png file 
    //---------------------------
    ChartUtilities.saveChartAsPNG(new java.io.File("mychart.png"), chart, 500, 500)
    
    // Show Chart in a Java Swing Frame
    //--------------------------------------
    val frame = new javax.swing.JFrame()
    frame.add(new ChartPanel(chart))
    frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE)
    frame.setSize(693, 513)
    frame.setTitle("Sample Pie Chart")
    frame.setVisible(true)
    

    It will display this chart:

    jfreeChart1.png

    1. Running the file src/jfreeChart1.scala
    # It will create the file jfreeChart1.jar 
    $ scala -cp lib/jcommon.jar:lib/jfreechart.jar -save jfreeChart1.scala 
    
    # The second time this command is run, it will run the file
    # jfreeChart1.jar that is a faster than run jfreeChart1.scala.
    $ scala -cp lib/jcommon.jar:lib/jfreechart.jar -save jfreeChart1.scala 
    
    # The produced jar file can be run directly with Scala.
    $ scala -cp lib/jcommon.jar:lib/jfreechart.jar -save jfreeChart1.jar
    
    1. Building an uber jar or fat-jar for easier distribution and deployment. A fat is a jar file bundled with all dependencies and runt-time libraries which makes possible to run the jar-file without Scala or JFree chart available at the deployment machine.

    This procedure uses the script: jar-tools.sh

    $ jar-tools.sh -scala-build-jar out/jfreeChart1-fat.jar jfreeChart1.jar lib/*
    
    At directory /home/archbox/test/out/temp
    Extracting /home/archbox/test/lib/jcommon.jar
    Extracting /home/archbox/test/lib/jfreechart.jar
    
    Manifest Content META-INF/MANIFEST.MF
    
    Manifest-Version: 1.0
    Scala-Compiler-Version: 2.11.8
    Main-Class: Main
    
    Building fat-jar file ...
    added manifest
    adding: com/(in = 0) (out= 0)(stored 0%)
    adding: com/keypoint/(in = 0) (out= 0)(stored 0%)
    adding: com/keypoint/PngEncoder.class(in = 9079) (out= 4645)(deflated 48%)
    adding: library.properties(in = 187) (out= 135)(deflated 27%)
    adding: Main$$anon$1.class(in = 1967) (out= 1031)(deflated 47%)
    adding: Main.class(in = 556) (out= 469)(deflated 15%)
    adding: Main$.class(in = 570) (out= 372)(deflated 34%)
    ignoring entry META-INF/
    
    ... ... ... ... ... ... ... ... ... ... ... ... ... ...
    
    adding: scala/Predef$StringFormat$.class(in = 2107) (out= 1010)(deflated 52%)
    adding: scala/Tuple5$.class(in = 1805) (out= 768)(deflated 57%)
    adding: scala/Function2$mcZJD$sp.class(in = 323) (out= 196)(deflated 39%)
    adding: scala/Char.class(in = 6084) (out= 3604)(deflated 40%)
    adding: scala/Float.class(in = 5382) (out= 3268)(deflated 39%)
    adding: scala/Enumeration$ValueSet$$anon$2.class(in = 1673) (out= 668)(deflated 60%)
    --------------------------------------
    
    Built file: out/jfreeChart1-fat.jar Ok.
    Run it with $ java -jar out/jfreeChart1-fat.jar
    

    The uber jar can be run by using the line below or by double clicking at the jar file if the system is configured properly:

    $ java -jar out/jfreeChart1-fat.jar
    

    This jar-file can be turned into a Unix executable with:

    $ jar-tools.sh -jar-to-sh out/jfreeChart1-fat.jar out/jfreeChart1.sh
    Build jar-executable out/jfreeChart1.sh
    Run it with ./out/jfreeChart1.sh
    
    $ file out/jfreeChart1.sh 
    out/jfreeChart1.sh: a /usr/bin/env sh  script executable (binary data)
    
    $ head -n 3 out/jfreeChart1.sh 
    #!/usr/bin/env sh 
    java -jar $0
    exit 0
    

    It can be executed with:

    $ ./out/jfreeChart1.sh
    

    1.6 C# Delegates in Scala

    1.6.1 Delegates in C#

    C#'s delegate works in a similar way to C or C++ function pointers and can hold reference instance method, static method or lambda function.

    Use cases:

    • Implement callbacks
    • Decouple classes: A class can call directly a method or static of another class without it implement any known interface. In addition to the indirect method call, delegates also allow lambda functions to be passed as arguments.

    Examples in Mono (C# Shell):

    • Point to static class method.
    $ csharp
    Mono C# Shell, type "help;" for help
    
    Enter statements below.
    csharp>
    
    // Create a function pointer which can point to
    // any function of type:
    //
    // ==>  double => double
    //     (input)     (output)
    //------------------------------------------------
    csharp> public delegate double MathFunc(double x);
    csharp>
    
    csharp> double pi = 3.1415
    
    // Create an empty delegate initially set to null
    csharp> MathFunc mfun;
    csharp>
    
    // ========= Supposed to fail throwing Null exception =========== //
    //
    csharp> mfun == null
    true
    csharp>
    
    csharp> mfun(pi)
    System.NullReferenceException: Object reference not set to an instance of an object
      at <InteractiveExpressionClass>.Host (System.Object& $retval) [0x00000]
      ...
    csharp>
    
    csharp> mfun.Invoke(pi)
    System.NullReferenceException: Object reference not set to an instance of an object
    
    // ========= Point to Math.Sin static method =========== //
    //
    csharp> mfun = Math.Sin
    csharp>
    
    csharp> mfun == null
    false
    csharp>
    
    // Ok - Supposed to return zero or very close to zero.
    csharp> mfun(pi)
    9.26535896604903E-05
    csharp>
    csharp> mfun.Invoke(pi)
    9.26535896604903E-05
    csharp>
    
    csharp> mfun(pi/2.0)
    0.999999998926914
    
    csharp> mfun.Invoke(pi/2.0)
    0.999999998926914
    
    
    // ========= Point to Math.Cos static method =========== //
    //
    csharp> mfun = Math.Cos
    
    // cos(pi) = cos(180 degrees) =~ -1
    csharp> mfun(pi)
    -0.999999995707656
    
    csharp> mfun.Invoke(pi)
    -0.999999995707656
    
    // cos(pi/2) = cos(90 degrees) =~ 0
    csharp> mfun(pi/2)
    4.63267948799578E-05
    

    Point to an instance's method.

    // Linear Equation f(x) = a * x + b
    class LinFun{
            private double _a = 0.0;
            private double _b = 0.0;
    
            public LinFun(double a, double b){
                    _a = a;
                    _b = b;
            }
    
            public void SetA(double a){
                    _a = a;
            }
    
            public void SetB(double b){
                    _b = b;
            }
    
            public double Compute(double x){
                    return _a * x + _b;
            }        
    }
    
    csharp> public delegate double MathFunc(double x);
    csharp>
    
    csharp> var linFun = new LinFun(3.0, 4.0);
    csharp>
    
    // Compute equation f(x) = 3 * x + 4
    //
    csharp> mfun = linFun.Compute ;
    csharp>
    
    csharp> mfun(0.0)
    4
    csharp> mfun(1.0)
    7
    csharp> mfun(2.0)
    10
    csharp> mfun(3.0)
    13
    csharp> mfun(4.0)
    16
    csharp>
    
    
    // Compute y(x) = 2 * x + 0.0
    //
    csharp> linFun.SetA(2.0)
    csharp> linFun.SetB(0.0)
    csharp>
    csharp> mfun(0.0)
    0
    csharp> mfun(1.0)
    2
    csharp> mfun(2.0)
    4
    csharp> mfun(4.0)
    8
    
    csharp> mfun.Invoke(1.0)
    2
    csharp> mfun.Invoke(2.0)
    4
    csharp> mfun.Invoke(3.0)
    6
    csharp>
    

    Point static methods of a custom class:

    class MathModule{
            public static double Square(double x){
                    return x * x;
            }
    
            public static double Triple(double x){
                    return 3.0 * x;
            }
    }
    
    csharp> public delegate double MathFunc(double x);
    
    csharp> mfun = MathModule.Square 
    csharp> mfun.Invoke(3.0)
    9
    csharp> mfun.Invoke(4.0)
    16
    csharp> mfun.Invoke(5.0)
    25
    csharp>
    
    csharp> mfun = MathModule.Triple
    csharp> mfun.Invoke(3.0)
    9
    csharp> mfun.Invoke(4.0)
    12
    csharp> mfun(5.0)
    15
    csharp>
    

    Point to a lambda function (aka anonymous function):

    csharp> mfun = x => 5.0 * x + 10.0
    csharp> 
    
    csharp> mfun = x => 5.0 * x + 10.0
    csharp> 
    csharp> mfun(0.0)
    10
    csharp> mfun(1.0)
    15
    csharp> mfun(2.0)
    20
    csharp> mfun(3.0)
    25
    csharp>
    

    Decouple classes:

    class TableBuilder{
            private double _xmin = 0;
            private double _xmax = 10.0;
            private double _step = 1.0;
    
            public void SetRange(double xmin, double xmax, double step = 0.1){
                    _xmin = xmin;
                    _xmax = xmax;
                    _step = step;
                    Console.WriteLine("Set xmin = {0} xmax = {1} step = {2} ", _xmin, _xmax, _step);
            }
    
            public void Show(MathFunc fn){
                    for(double x = _xmin; x < _xmax; x = x + _step){
                            Console.WriteLine("x = {0:F3}\ty={1:F3}", x, fn(x));
                    }
            }        
    }
    
    
    csharp> var linFunService = new LinFun(4.0, 5.0)
    
    // Compute table for y(x) = 4.0 * x + 5.0
    csharp> tableBuilder.Show(linFunService.Compute)
    x = 0.000   y=5.000
    x = 1.000   y=9.000
    x = 2.000   y=13.000
    x = 3.000   y=17.000
    x = 4.000   y=21.000
    x = 5.000   y=25.000
    x = 6.000   y=29.000
    x = 7.000   y=33.000
    x = 8.000   y=37.000
    x = 9.000   y=41.000
    csharp> 
    
    // Compute table for y(x) = 3.0 * x + 4.0
    csharp> linFunService.SetA(3.0)
    csharp> linFunService.SetB(0.0)
    csharp> 
    csharp> tableBuilder.Show(linFunService.Compute)
    x = 0.000   y=0.000
    x = 1.000   y=3.000
    x = 2.000   y=6.000
    x = 3.000   y=9.000
    x = 4.000   y=12.000
    x = 5.000   y=15.000
    x = 6.000   y=18.000
    x = 7.000   y=21.000
    x = 8.000   y=24.000
    x = 9.000   y=27.000
    csharp> 
    
    // Compute table for static method Sin of class Math.        
    csharp> tableBuilder.Show(Math.Sin)
    x = 0.000   y=0.000
    x = 1.000   y=0.841
    x = 2.000   y=0.909
    x = 3.000   y=0.141
    x = 4.000   y=-0.757
    x = 5.000   y=-0.959
    x = 6.000   y=-0.279
    x = 7.000   y=0.657
    x = 8.000   y=0.989
    x = 9.000   y=0.412
    csharp>
    
    // Compute table using lambda function         
    csharp> tableBuilder.Show(x => 2 * x + 3)
    x = 0.000   y=3.000
    x = 1.000   y=5.000
    x = 2.000   y=7.000
    x = 3.000   y=9.000
    x = 4.000   y=11.000
    x = 5.000   y=13.000
    x = 6.000   y=15.000
    x = 7.000   y=17.000
    x = 8.000   y=19.000
    x = 9.000   y=21.000
    csharp>
    

    1.6.2 Delegates in Scala

    A delegate in Scala can be just a variable of function type. As in C#, it can hold reference to instance methods, static methods and lambda functions.

    Declare delegate type.

    // C#: public delegate double MathFunc(double x)
    type MathFunc = Double => Double
    

    Create delegate variable:

    // Initialize with NULL -> Null is evil, but it will be used for the sake of testing
    // and experimentation.
    //
    scala> var mfun: MathFunc = null
    mfun: MathFunc = null
    
    // Approximate value of PI
    scala> val pi = 3.1415
    pi: Double = 3.1415
    
    scala> mfun(pi)
    java.lang.NullPointerException
      ... 28 elided
    

    Point to lambda function:

    //----- Point to Lambda Function ------------------------//
    //
    scala> mfun = x => 3.0 * x + 5.0
    mfun: MathFunc = $$Lambda$1097/302990364@2407f1a8
    
    scala> mfun(0.0)
    res13: Double = 5.0
    
    scala> mfun(1.0)
    res14: Double = 8.0
    
    scala> mfun(2.0)
    res15: Double = 11.0
    
    scala> val someLambda = (x: Double) => x * x
    someLambda: Double => Double = $$Lambda$1277/1466120795@6fbd56da
    
    scala> mfun(0.0)
    res36: Double = 0.0
    
    scala> mfun(2.0)
    res37: Double = 4.0
    
    scala> mfun(5.0)
    res38: Double = 25.0
    

    Point to static method:

    //----- Point to java.lang.Math.cos static method ----------//
    //
    scala> mfun = java.lang.Math.cos
    mfun: MathFunc = $$Lambda$1078/2000449863@5abc5854
    
    scala> mfun(pi)
    res2: Double = -0.9999999957076562
    
    scala> mfun(Math.PI)
    res3: Double = -1.0
    
    scala> mfun(Math.PI / 2.0)
    res4: Double = 6.123233995736766E-17
    
    //------- Point to Math.log10 (Logarithm of base 10)  -------//
    //
    scala> mfun = Math.log10
    mfun: MathFunc = $$Lambda$1080/61227510@66487713
    
    scala> mfun(1.0)
    res7: Double = 0.0
    
    scala> mfun(10.0)
    res8: Double = 1.0
    
    scala> mfun(100.0)
    res9: Double = 2.0
    

    Point to instance method:

    class LinFun(a: Double, b: Double){
      private var _a: Double = a
      private var _b: Double = b
    
      def setA(a: Double) =
        _a = a
    
      def setB(b: Double) =
        _b = b
    
      def compute(x: Double): Double =
        _a * x + _b
    }
    
    • Running:
    scala> val linFun = new LinFun(3.0, 4.0)
    linFun: LinFun = LinFun@6f45872b
    
    scala> linFun.compute(0.0)
    res16: Double = 4.0
    
    scala> linFun.compute(1.0)
    res17: Double = 7.0
    
    scala> linFun.compute(2.0)
    res18: Double = 10.0
    
    scala> mfun = linFun.compute
    mfun: MathFunc = $$Lambda$1247/485914296@501904ff
    
    scala> mfun(0.0)
    res21: Double = 4.0
    
    scala> mfun(1.0)
    res22: Double = 7.0
    
    scala> mfun(2.0)
    res23: Double = 10.0
    
    
    // Compute now 2 * x + 0
    //------------------------
    scala> linFun.setA(2.0)
    scala> linFun.setB(0.0)
    
    scala> mfun(0.0)
    res27: Double = 0.0
    
    scala> mfun(1.0)
    res28: Double = 2.0
    
    scala> mfun(5.0)
    res29: Double = 10.0
    
    scala> mfun.apply(0.0)
    res30: Double = 0.0
    
    scala> mfun.apply(1.0)
    res31: Double = 2.0
    
    scala> mfun.apply(3.0)
    res32: Double = 6.0
    

    Decouple Classes

    class TableBuilder{
      private var _xmin: Double = 0;
      private var _xmax: Double = 10.0;
      private var _step: Double = 1.0;
    
      def setRange(xmin: Double, xmax: Double, step: Double = 0.1){
        _xmin = xmin;
        _xmax = xmax;
        _step = step;
        println("Set xmin = {0} xmax = {1} step = {2} ", _xmin, _xmax, _step);
      }
    
      def show(fn: MathFunc) =
        for(x <- _xmin to _xmax by _step)
          println(f"x = $x%.3f\t y = ${fn(x)}%.3f")
    }
    

    Running:

    Note: The class TableBuilder does not need to know anything about the class linFun.

    • Pass static method as argument
    scala> tbl.show(Math.sin)
    x = 0.000        y = 0.000
    x = 1.000        y = 0.841
    x = 2.000        y = 0.909
    x = 3.000        y = 0.141
    x = 4.000        y = -0.757
    x = 5.000        y = -0.959
    x = 6.000        y = -0.279
    x = 7.000        y = 0.657
    x = 8.000        y = 0.989
    x = 9.000        y = 0.412
    x = 10.000       y = -0.544
    
    • Pass instance method as argument
    scala> val linFun = new LinFun(3.0, 4.0);
    linFun: LinFun = LinFun@27a65db7
    
    // Note: Class TableBuilder does not need to know anything about class LinFun
    scala> tbl.show(linFun.compute)
    x = 0.000        y = 4.000
    x = 1.000        y = 7.000
    x = 2.000        y = 10.000
    x = 3.000        y = 13.000
    x = 4.000        y = 16.000
    x = 5.000        y = 19.000
    x = 6.000        y = 22.000
    x = 7.000        y = 25.000
    x = 8.000        y = 28.000
    x = 9.000        y = 31.000
    x = 10.000       y = 34.000
    
    scala> linFun.setA(2.0)
    scala> linFun.setB(0.0)
    scala> tbl.show(linFun.compute)
    x = 0.000        y = 0.000
    x = 1.000        y = 2.000
    x = 2.000        y = 4.000
    x = 3.000        y = 6.000
    x = 4.000        y = 8.000
    x = 5.000        y = 10.000
    x = 6.000        y = 12.000
    x = 7.000        y = 14.000
    x = 8.000        y = 16.000
    x = 9.000        y = 18.000
    x = 10.000       y = 20.000
    
    • Pass lambda function as argument
    // Show constant function  
    scala> tbl.show(x => 10.0)
    x = 0.000        y = 10.000
    x = 1.000        y = 10.000
    x = 2.000        y = 10.000
    x = 3.000        y = 10.000
    x = 4.000        y = 10.000
    x = 5.000        y = 10.000
    x = 6.000        y = 10.000
    x = 7.000        y = 10.000
    x = 8.000        y = 10.000
    x = 9.000        y = 10.000
    x = 10.000       y = 10.000
    
    • Pass non compatible function as argument using lambda.
    scala> def binFun(x: Double, y: Double) = 5 * x + 4 * y - 10.0
    binFun: (x: Double, y: Double)Double
    
    scala> tbl.show(a => binFun(5.0, a))
    x = 0.000        y = 15.000
    x = 1.000        y = 19.000
    x = 2.000        y = 23.000
    x = 3.000        y = 27.000
    x = 4.000        y = 31.000
    x = 5.000        y = 35.000
    x = 6.000        y = 39.000
    x = 7.000        y = 43.000
    x = 8.000        y = 47.000
    x = 9.000        y = 51.000
    x = 10.000       y = 55.000
    

    1.6.3 Multicast Delegate

    class MulticastDelegate[A]{
      import scala.collection.mutable.ListBuffer
      private val _lst = new ListBuffer[A => Unit]()
    
      def :=(fn: A => Unit) =
        _lst.append(fn)
    
      def +=(fn: A => Unit) =
        _lst.append(fn)
    
      def apply(x: A) =
        for(fun <- _lst) fun(x)
    }
    
    // Singleton: Class of a single instance
    object Operations{
      def add(x: Double, y: Double) =
        println(s"add(x = $x, y = $y) = ${x + y}")
    
      def mul(x: Double, y: Double) =
        println(s"mul(x = $x, y = $y) = ${x * y}")
    }
    
    val mt = new MulticastDelegate[(Double, Double)]
    
    // Acknowledgment: Thanks to the gits https://gist.github.com/jfrazee/6271143
    scala> mt += (Operations.add _).tupled
    
    scala> mt += (Operations.mul _).tupled
    
    scala> mt += { case (x: Double, y: Double) => println("fn(x, y) = " + (3 * x + 4 * y))}
    
    scala> mt(4.0, 5.0)
    add(x = 4.0, y = 5.0) = 9.0
    mul(x = 4.0, y = 5.0) = 20.0
    fn(x, y) = 32.0
    
    scala> mt.apply(3.0, 5.0)
    add(x = 3.0, y = 5.0) = 8.0
    mul(x = 3.0, y = 5.0) = 15.0
    fn(x, y) = 29.0
    
    scala> val t = (4.0, 10.0)
    t: (Double, Double) = (4.0,10.0)
    
    scala> mt(t)
    add(x = 4.0, y = 10.0) = 14.0
    mul(x = 4.0, y = 10.0) = 40.0
    fn(x, y) = 52.0
    

    1.6.4 References and further reading

    Author: nobody

    Created: 2018-06-17 Sun 05:42

    Emacs 25.3.1 (Org mode 8.2.10)

    Validate