How to Scala, Written by a Java: 2 – Classes and Objects

(Find these examples at my GitHub))

Classes in scala are defined in a similar manner to how they are defined in Java.

class ClassBasic{
  
}

This is the simplest possible class. It has no constructor. It has no methods. It does nothing. Its uninteresting.

1. Constructors

Let’s give it a constructor.

class ClassBasic(_number: Int){
  private val number = _number
}

In Scala, the constructor is defined by the class body itself. the arguments to the constructor are placed after the class name. The body of the constructor is accounted by the statements and expressions in the body of the class.

To make the constructor private or protected you place the appropriate word before the arguments. The default access level in Scala is public.

class ClassBasic private(_number: Int){
  private val number = _number
}

Since the body of the class is the constructor body, there is a very limited sense of constructor overloading in Scala. You cannot have two different constructors that do wildly different things. However you can create overloaded constructors by calling another constructor.

class ClassBasic(_number: Int){
  def this(numberString: String) = this(numberString.toInt)
  def this() = this(0)
  
  private val number = _number
}

Here we have three constructors. The first constructor takes an Int and sets a member to the argument’s value. The second takes a String and calls the first constructor on the Int representation of the passed in String. The third takes no arguments and is a simple currying of the first constructor. All three of them at the end of the day call the same code.

Let’s make our class a little more interesting for the rest of the post.

class ClassBasic(_number: Int, _text: String){
  def this(_text: String) = this(0, _text)
  def this(_number: Int) = this(_number, "")
  
  private val number = _number
  private val text = _text
  
  private val concat = text + number
}

2. Methods

Methods are simply functions within a class. You define them like any other function.

  def getNumber(): Int = {
    number
  }
  def getText(): String = {
    text
  }
  def getValue(): String = {
    concat
  }

These define the get methods for the members of the class. More succinctly, we may write:

  def getNumber(): Int = number
  def getText(): String = text
  def getValue(): String = concat

Finally we’ll give our class all the bells and whistles by overriding the toString, equals and hashCode methods. In Scala, every method which override a method defined in a super class must be labelled with override.

  override def toString(): String = {
    "number = " + number + "\n" +
    "text = " + text + "\n" +
    "concat = " + concat
  }
  override def equals(any: Any): Boolean = {
    if(!any.isInstanceOf[ClassBasic]){
      false
    }
    else{
      val other = any.asInstanceOf[ClassBasic]
      (getNumber() equals other.getNumber()) &&
      (getText() equals other.getText())
    }
  }
  override def hashCode(): Int = concat.hashCode()

3. Non-instance Members

Non-instance members are typically referred to as static. These are members of the class which exist outside any instance of the class. In Scala, there is a clear distinction between instance and non-instance class members. The keyword object implies the members within exist outside the class instances. In Java terms the object is where all the static members of the class would be written. Taking advantage of this is easy. Our class becomes:

object ClassBasic{
  private val DEFAULT_NUMBER = 0
  private val DEFAULT_TEXT = ""
}
class ClassBasic(_number: Int, _text: String){
  def this(_text: String) = this(ClassBasic.DEFAULT_NUMBER, _text)
  def this(_number: Int) = this(_number, ClassBasic.DEFAULT_TEXT)
  
  private val number = _number
  private val text = _text
  
  private val concat = text + number
  
  def getNumber(): Int = number
  def getText(): String = text
  def getValue(): String = concat
  
  override def toString(): String = {
    "number = " + number + "\n" +
    "text = " + text + "\n" +
    "concat = " + concat
  }
  override def equals(any: Any): Boolean = {
    if(!any.isInstanceOf[ClassBasic]){
      false
    }
    else{
      val other = any.asInstanceOf[ClassBasic]
      (getNumber() equals other.getNumber()) &&
      (getText() equals other.getText())
    }
  }
  override def hashCode(): Int = concat.hashCode()
}

We say this is the class ClassBasic and its companion object. The companion object is defined in the same file as the class, takes the same name as the class and has access to all the members of the class. Likewise, the class has access to all the members of its companion object. Common uses are holding non-instance members and creating factory methods for your class (note the singleton is a special case of the factory).

  //factory
  def apply(number: Int, text: String): ClassBasic =
    new ClassBasic(number, text)
  def apply(number: Int): ClassBasic =
    new ClassBasic(number)
  def apply(text: String): ClassBasic =
    new ClassBasic(text)

The apply method is a special method in Scala. The language provides some syntactic sugar to make calling this method easy. The following two code snippets are provide the same results.

val number = 9
val text = "nine"
val basic1 = ClassBasic.apply(number, text)
val basic2 = ClassBasic.apply(number)
val basic3 = ClassBasic.apply(text)
println(basic1 + "\n" + basic2 + "\n" + basic3)
val number = 9
val text = "nine"
val basic1 = ClassBasic(number, text)
val basic2 = ClassBasic(number)
val basic3 = ClassBasic(text)
println(basic1 + "\n" + basic2 + "\n" + basic3)

Next we’ll take a look at for comprehensions.

Advertisements

How to Scala, Written by a Java: 1 – Functions

(Find these examples at my GitHub))
I, like many others breaking into Scala come from a Java background. I found one of the largest hurdles to using Scala effectively was getting used to functions as a data type: functions are first class citizens in Scala.

Functional Basics

Functions may be assigned to values and variables, passed into other functions as arguments, and returned by functions. Let’s take for instance a simple function which takes as arguments three integer arguments and returns a double representing the sum of the first two arguments divided by the third.

def foo(sum1: Int, sum2: Int, divisor: Int): Double={
  val sum = sum1 + sum2
  sum.toDouble / divisor.toDouble
}

1. Currying

Say, you have a need for a function which takes an int adds 3 to it then divides that sum by 4. at this point we could write a new function:

def plus3Over4AsNew(arg: Int): Double={
  val sum = arg + 3
  sum.toDouble / 4.0
}

But, this is very reminiscent of foo. Its the same code with immediate values in place of a couple variables. Luckily in Scala we can avoid the extra typing by creating a curried function.

If f(x, y, z) is a function, a currying of f would partially apply f over one or more of its arguments: g(x) = f(x, 3, 4) in our case. So, back to our example.

def plus3Over4(arg: Int): Double = foo(arg, 3, 4)

This helps us in a few ways. Most obviously, we save on typing. Secondly and more importantly, we save on maintenance; the curried function benefits from any optimizations or bug fixes applied to the first.

2. Functions as Arguments

Suppose you need to perform many different operations upon the result of summing two integers. Say, in one part of the application you need to divide the sum by 4 and in another part of the application you need to raise the result to the power of 4. We could write these as two separate functions:

def addThenDivideBy4AsNew(sum1: Int, sum2: Int): Double={
  val sum = sum1 + sum2
  sum / 4.0
}
def addThenPowerOf4AsNew(sum1: Int, sum2: Int): Double={
  val sum = sum1 + sum2
  Math.pow(sum, 4)
}

But, like before, there will be duplication of code. As both these functions sum the arguments before applying the final step. We can remove this duplication by having a function which takes the arguments to be summed and a third argument that is a function from Int to Double.

def addThen(sum1: Int, sum2: Int, function: (Int => Double)): Double={
  val sum = sum1 + sum2
  function(sum)
}
private def divideBy4(arg: Int): Double ={
  arg / 4.0
}
private def powerOf4(arg: Int): Double={
  Math.pow(arg, 4)
}
def addThenDivideBy4(sum1: Int, sum2: Int) =
  addThen(sum1, sum2, divideBy4)
def addThenPowerOf4(sum1: Int, sum2: Int) =
  addThen(sum1, sum2, powerOf4)

The syntax for declaring a function uses the ‘=>’ symbol (sometimes called ‘arrow’ or ‘missile’). To the left of the => lies the arguments. If using more than one argument, separate them by commas and surround the block by parentheses:

def multiArgumentFunctionFunction(
  multiArgumentFunction: ((Int, Int, Double) => Double)
): Double = 0.0

You can also pass in functions anonymously using the => operator and curly braces.

def addThenDouble(sum1: Int, sum2: Int): Double =
  addThen(sum1, sum2,
    {sum =>
      sum * 2.0
    }
  )

3. Functions as Values & Partially Applied Functions

This is pretty straight forward. You may assign functions to values (or variables) and pass them about your application:

val fourArgs: ((Int, Int, Int, Int) => Int) = {(a, b, c, d) =>
  a + b + c + d
}
def manyArgs(
  a: Int,
  b: Int,
  c: Int,
  d: Int,
  e: Int,
  f: Int,
  g: Int,
  h: Int,
  i: Int,
  j: Int
): Int={
  val first = fourArgs(a, b, c, d)
  
  val threeArgs: ((Int, Int, Int) => Int) = fourArgs(_, _, _, 4)
  val second = threeArgs(e,f,g)
  
  val twoArgs: ((Int, Int) => Int) = threeArgs(_, _, 0)
  val third = twoArgs(h, i)
  
  val oneArg: (Int => Int) = twoArgs(_, 7)
  val fourth = oneArg(j)
  
  fourArgs(first, second, third, fourth)
}

Scala makes extensive use of the ‘_’ operator. In this context, it implies the function is partially applied. A partially applied function is similar to currying. The difference is, a curried function returns the result of the underlying function where partial application provides another function object.

3. Closures

Again, functions are first-class citizens in Scala. This means they may be declared anywhere any other data type may be declared including within another function:

def function(): Int={
  def innerFunction() = 7
  innerFunction()
}

This will return 7. Like any other value, you may define a function using other values and variables in scope.

def function(): Int={
  var variable = 1
  def innerFunction(arg: Int): Int={
    val increment = variable * 2
    arg + increment
  }
  variable = innerFunction(variable)
  innerFunction(variable)
}

This will return 9.
The var variable is declared outside of innerFunction’s scope yet its able to be read and modified by innerFunction. This is similar to using final pointers in Java anonymous classes. But, what’s happening in Scala is the compiler sees a reference to variable but cannot find that reference in scope so it goes to the next scope up, function’s scope, and checks there, this continues until variable is found. All the references required by innerFunction is called the closure of innerFunction (think set theory). The compiler brings in what’s necessary and no more.
With closures, objects that are needed by multiple nested scopes can live on even after their enclosing scope is exited. As long as a function which closes over an object is still in play, that object is still in play.

Next we’ll take a look at how to create classes.

Scala – Delimited Continuations

(The examples can be found on my GitHub)

Like many others out there, the first time I saw a continuation it threw me for a loop. So, I took to Google to find an explanation of what the code was doing. This led me in circles. Hopelessly hopping from message board to message board trying to find an explanation that made sense to me. I could not find one. This is an abbreviation of my attempt at learning continuations by “hacking away” along with my contrived examples along the way. I take the form of a scientist running experiments for this exercise.

Here are the resources I found most useful in my journey:

0. Setup

Scala does not by default support continuations. You will need to enable the continuations compiler plugin by passing -P:continuations:enable.

Once the plugin is ready to go each of your scala source files which wants to utilize continuations should import the scala.util.continuations._ elements.

1. Example 1: Control Flow Basics

Let’s compose an application that performs a few println calls:

1.1 The skeleton

object Test extends App{
  def doContinuation{
    reset{
      shift{continuation: (Unit => Unit) =>
      }
    }
  }
  doContinuation
}

Here we have an application which calls reset with a shift that takes as an argument a function with no arguments and no output. The shift is empty. Running this will produce no result. 

1.2 Say Hello

Let’s add the seminal hello world print call.

  def doContinuation{
    reset{
      shift{continuation: (Unit => Unit) =>
      }
      println("Hello World!")
    }
  }

Here our reset prints hello world after it performs the shift. Well… not exactly. This function also produces no result. Let’s add another print.

  def doContinuation{
    reset{
      println("Before shift")
      shift{continuation: (Unit => Unit) =>
      }
      println("Hello World!")
    }
  }

Now we have prints before and after the shift. We would expect to see before shift then hello world printed. Running this gives us before shift but still no hello world. Let’s add a third print.

  def doContinuation{
    reset{
      println("Before shift")
      shift{continuation: (Unit => Unit) =>
        println("shift")
      }
      println("Hello World!")
    }
  }

Adding a print within the shift prints before shift, followed by shift then program termination. So far we have three pieces of information:

  1. Tasks given before the shift are always performed
  2. Tasks given within the shift are always performed
  3. Tasks given after the shift may not be performed

Point 3 says “may not” rather than “won’t” because we have yet to have done enough testing to make such a strong claim.

Taking a look at the application, we see we have one object sitting around that we have yet to play with: the argument into shift. Let’s use this function.

  def doContinuation{
    reset{
      println("Before shift")
      shift{continuation: (Unit => Unit) =>
        println("start shift")
        continuation()
        println("end shift")
      }
      println("Hello World!")
    }
  }

Running this we finally get out hello world to print! But, it prints where the function continuation is placed in the control flow not where someone who comes from Java (such as myself) would expect it to be called.

1.3 Trying to understand what just happened.

Let’s change the hello world print to something more appropriate and examine the output:

  def doContinuation{
    reset{
      println("Before shift")
      shift{continuation: (Unit => Unit) =>
        println("start shift")
        continuation()
        println("end shift")
      }
      println("after shift")
    }
  }

Which produces:

Before shift
start shift
after shift
end shift

So, it seems the code after the shift is performed within the shift by the call to the argument of shift. In other words: the function that is argument to shift captures the code within the reset block after the shift. To test this let’s get a bit fancier within our shift.

  def doContinuation{
    reset{
      println("Before shift")
      shift{continuation: (Unit => Unit) =>
        println("start shift")
        continuation()
        println("between1")
        continuation()
        println("between2")
        continuation()
        println("end shift")
      }
      println("after shift")
    }
  }

Which produces:

Before shift
start shift
after shift
between1
after shift
between2
after shift
end shift

Here in each case where continuation is called, the code after shift is called. This implies the code after shift is used as the argument into shift which shift uses to determine the control flow of the reset operation.

2. Example 2: Argument and Return Value Basics

Let’s compose an application which counts natural numbers.

2.1 The skeleton

object Test extends App{
  def doContinuation{
    println("entering reset")
    reset{
      println("before shift")
      shift{cont: (Unit => Unit) =>
        println("start shift")
        cont()
        println("end shift")
      }
      println("after shift")
    }
    println("exited reset")
  }
  doContinuation
}

2.2 The Argument

Say we want our continuation to perform actions on Int objects.Then our continuation would need to take an Int as an argument.

  def doContinuation{
    println("entering reset")
    reset{
      println("before shift")
      shift{cont: (Int => Unit) =>
        println("start shift")
        cont(0)
        println("end shift")
      }
      println("after shift")
    }
    println("exited reset")
  }

We’ve changed shift’s input function to take an Int and produce a Unit but, what does this mean in our reset context? What represents the input? The shift itself represents the input. Let’s add more to our application.

  def doContinuation{
    println("entering reset")
    reset{
      println("before shift")
      val argument =
        shift{cont: (Int => Unit) =>
          println("start shift")
          cont(0)
          println("end shift")
        }
      println("after shift " + argument)
    }
    println("exited reset")
  }

This produces:

entering reset
before shift
start shift
after shift 0
end shift
exited reset

Within the shift, the value passed into the continuation(Int) function is delivered to the reset as the shift itself. This allows us to set a value to shift then use that value in our continuation.

2.3 The Return Value

Say we want our continuation to increment Int objects. Then we would need to take an Int as argument and return one as a result.

  def doContinuation{
    println("entering reset")
    reset{
      println("before shift")
      val argument =
        shift{cont: (Int => Int) =>
          println("start shift")
          cont(0)
          println("end shift")
        }
      println("after shift " + argument)
      argument + 1
    }
    println("exited reset")
  }

This produces the same result as the last code snippet but it opens up a few possibilities. Now, we can call the continuation inside our shift and transform our single input even further.

  def doContinuation{
    println("entering reset")
    reset{
      println("before shift")
      val argument =
        shift{cont: (Int => Int) =>
          println("start shift")
          cont(cont(cont(0)))
          println("end shift")
        }
      println("after shift " + argument)
      argument + 1
    }
    println("exited reset")
  }

This produces:

entering reset
before shift
start shift
after shift 0
after shift 1
after shift 2
end shift
exited reset

To count from an Int until any other you compose the continuation their difference, then start with the original figure. This will of course be incredibly annoying and eventually result in a stack overflow. The following procudes 10 to 12 without the fluff:

object Test extends App{
  def doContinuation(start: Int, end: Int){
    val count = end - start
    println("entering reset")
    reset{
      println("before shift")
      val argument =
        shift{cont: (Int => Int) =>
          println("start shift")
          var current = cont(start)
          1 to count foreach{num=>
            current = cont(current)
          }
          println("end shift")
        }
      println("after shift " + argument)
      argument + 1
    }
    println("exited reset")
  }
  
  doContinuation(10, 12)
}

3. Example 3: Increasing Complexity

3.1 The skeleton

Lets say we wanted a List[Int] from 1 to some Int.

object Test extends App{
  def doContinuation(count: Int): List[Int]={
    val buffer: Buffer[Int] = Buffer()
    reset{
      val curr =
        shift{cont: (Int => Any) =>
          1 to count foreach{num =>
            cont(num)
          }
        }
      buffer += curr
    }
    buffer toList
  }
  
  println(doContinuation(10))
}

This results in:

List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Not surprising given what we’ve learned from the above.

3.2 Continuation Composition

Let’s take this one step further and make a list of lists of this kind using continuations.

  def doContinuation(count: Int): List[List[Int]]={
    val buffer: Buffer[List[Int]] = Buffer()
    reset{
      val curr =
        shift{cont: (Int => Any) =>
          1 to count foreach{num =>
            cont(num)
          }
        }
      buffer += List(curr)
    }
    buffer toList
  }

This gives us:

List(List(1), List(2), List(3), List(4), List(5), List(6), List(7), List(8), List(9), List(10))

Not too exciting yet but we’ll get there. Recall when I said the function that is argument to shift captures the code within the reset block after the shift. This statement is all inclusive. Let’s take a look.

  def doContinuation(count: Int): List[List[Int]]={
    val buffer: Buffer[Buffer[Int]] = Buffer()
    reset{
      val first =
        shift{cont: (Int => Any) =>
          0 to count foreach{num =>
            cont(num)
          }
        }
      val innerBuffer: Buffer[Int] = Buffer()
      buffer += innerBuffer
      val second=
        shift{cont: (Int => Any) =>
          1 to count foreach{num =>
            cont(first + num)
          }
        }
      innerBuffer += second
    }
    buffer.
      toList.
      map{element => element toList}
  }

This results in (formatted for readability):

List(
  List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
  List(2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  List(3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
  List(4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
  List(5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
  List(6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
  List(7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
  List(8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
  List(9, 10, 11, 12, 13, 14, 15, 16, 17, 18),
  List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19),
  List(11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
)

The first shift’s continue contains within it, the second shift. So, the continuation for the first shift creates a new buffer which it appends to the function scope buffer then calls the second shift. The continuation for the second shift appends its value to the buffer created by the continuation for the first shift.

Scala – Deployable Eclipse plugin

Download Example from my GitHub.

To get started

  1. Eclipse >= 3.5 (This tutorial uses 4.3 Kepler)
  2. Eclipse should have plugin development installed
  3. Eclipse should have the Scala IDE installed (this tutorial uses 3.0.2)

1. Create a simple Eclipse Plugin

  1. Open the dialog File->New->Other…
  2. Select Plug-in Project from the list
  3. Enter com.dreadedsoftware.example.eclipse.plugin.scala for the name (Fig 1.1)
  4. Click Next until you reach the “Templates” Wizard Page
  5. Select the “Hello, World Command” option (Fig 1.2)
  6. Click “Finish”

Fig 1.1

Image\

Fig 1.2

Image

2. Scalafy your project

  1. Right Click on your project
  2. Configure->Add Scala Nature (Fig 2.1)
  3. Convert SampleHandler.java to Scala
    1. Right click on the file
    2. Convert to Scala (Fig 2.2)
    3. You’ll see the Convert to Scala Dialog (Fig 2.3)
      1. Select the src folder of your project
      2. Check “Delete Java after Conversion”
      3. “Append original Java as a comment…” is optional
      4. Click OK
    4. You should be left with something like Fig 2.4

Fig 2.1

Image

Fig 2.2

Image

Fig 2.3

Image

Fig 2.4

Image

3. Launch your project

  1. Right click on your project
  2. Run As->Eclipse Application (Fig 3.1)
  3. A new Eclipse instance should begin
  4. In the new Eclipse instance select Sample Menu->Sample Command (Fig 3.2)
  5. A box representing the text in Fig 2.4 will appear…
  6. Or It won’t…

Fig 3.1

Image

Fig 3.2

Image

4. What Happened?

The eclipse plugin builder doesn’t know about scala files even though Eclipse as a whole understands what they are and that they can interact with java files. When the plugin gets packaged into a jar, the build system builds the java files and then just copies the other files in src over into the build. We can have Eclipse illustrate this interaction for us:

  1. Open the META-INF/MANIFEST.MF file
  2. Click the Export button (Fig 4.1 circled in red)
  3. Choose a comfortable destination and click finish
  4. Open the exported jar file in any zip viewer
  5. Inside the zip file navigate to the “com\dreadedsoftware\example\eclipse\plugin\scala\handlers\” folder
  6. Note there is a scala file rather than a class file present (Fig 4.2)

Fig 4.1

Image

Fig 4.2

Image

5. The Solution

  1. Open the META-INF/MANIFEST.MF file
  2. Open the “Runtime” tab
  3. Note the “Classpath” section
  4. Click the “Add…” button (Fig 5.1)
  5. Select the “bin” folder (Fig 5.2)
  6. Click OK
  7. Open the “Build” tab
  8. Note the “Binary Build” section
  9. Make sure “bin” is checked (Fig 5.3)
  10. Launch your project again and the Hello popup should be displayed

Fig 5.1

Image

Fig 5.2

Image

Fig 5.3

Image