Skip to content

Latest commit

 

History

History
1357 lines (1032 loc) · 34.3 KB

PRACTICAL_RECIPES.org

File metadata and controls

1357 lines (1032 loc) · 34.3 KB

Scala Recipes

Scala Recipes - Examples about integration with Java

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

Java Reflection

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

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()
...

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)

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
...

GUI - Graphical User Interface (Java Swing)

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")

images/messageBox1.png

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) }

images/passwordGui1.png

images/passwordGui2.png

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"))

images/listViewFiles.png

Show java properties

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

images/listViewJavaProperties.png

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")

images/textView1.png

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()))

images/clockDisplayGui.png

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"
}

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:

images/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

C# Delegates in Scala

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>         

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

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

References and further reading