Tommy Chheng

Icon

All Things Programming!

Partial functions in Scala

I ran into a problem where i wanted to get a formatted string for each tuple in a list but ended on a detour to learning about partial functions. Consider this simple case:

scala> val wordCount = List(("a",1),("b",2))
wordCount: List[(java.lang.String, Int)] = List((a,1), (b,2))

I can just use ._1 and ._2 on each tuple but it isn’t very readable. If someone else is reading the code, will they know what ._1 is for?

scala> wordCount.map(wc => wc._1+":"+wc._2)
res4: List[java.lang.String] = List(a:1, b:2)

We can use case classes to the rescue:

scala> wordCount.map(case(word,count) => word+":"+count)
:1: error: illegal start of simple expression
wordCount.map(case(word,count) => word+":"+count)
^

Opps, as dpp mentioned on the scala mailing list, case is a partial function so this syntax won’t work.

What is a partial function you ask?

Partial functions allow you to specify a subset of the parameters in a function. Imagine this trivial case where you have an add function.

scala> def add(t1:Int,t2:Int) = t1+t2
add: (t1: Int,t2: Int)Int

You can create a partial function addByOne which will have one parameter bounded and another unbounded.

scala> val addByOne = add(1,_:Int)
addByOne: (Int) => Int =<function1>

Then you can evaluate addByOne by specifying the unbounded parameter:

scala> addByOne(10)
res5: Int = 11

case: a Partial Function

Back to our original example why calling map with parentheses doesn’t work.
case is a partial function which will only be called if the isDefinedAt method is true. If it was a Function, it would throw a MatchError when no case matches are found.


scala> val myPartial:PartialFunction[Any,String]= {case(word,count) => word+":"+count}
myPartial: PartialFunction[Any,String] = <function1>

We can apply the partial function to each tuple explicitly:

scala> wordCount.map(x => myPartial(x))
res14: List[String] = List(a:1, b:2)

or with the implied argument:

scala> wordCount.map(myPartial)
res15: List[String] = List(a:1, b:2)

We can also pass the partial function as an anonymous function(or closure):

scala> wordCount.map({case(word,count) => word+":"+count})
res16: List[java.lang.String] = List(a:1, b:2)

and remove the the extra parentheses:

scala> wordCount.map {case(word,count) => word+":"+count}
res17: List[java.lang.String] = List(a:1, b:2)

Thanks to dpp for bringing partial functions to my attention.

When to call methods with or without parentheses () in Scala

I ran into this method call quirk in Scala:

If the method has no parameters, you must call it without the parentheses unless the method declaration was defined with empty parentheses.

If you are new to Scala, you’ll probably see this manifest when using iterators.

scala> val wordListIter = wordList.iterator()
:9: error: wordList.iterator of type Iterator[(java.lang.String, java.lang.String)] does not take parameters
scala> val wordListIter = wordList.iterator
wordListIter: Iterator[(java.lang.String, java.lang.String)] = non-empty iterator
scala> val lines= Source.fromPath(filename).getLines
:6: error: missing arguments for method getLines in class Source;
follow this method with `_' if you want to treat it as a partially applied function
Error occured in an application involving default arguments.
val lines= Source.fromPath(filename).getLines
scala> val lines= Source.fromPath(filename).getLines()
lines: Iterator[String] = non-empty iterator

It would have been helpful if the empty parens are listed for the getLines scalaDocs

The convention ensures the uniform access principle. This convention is unlike languages like Ruby where you can call parameter-less methods with or without parentheses.

This except from page 212 of Programming in Scala explains the rationale:

instead of:
def width(): Int
the method is defined without parentheses:
def width: Int

Such parameterless methods are quite common in Scala. By contrast, methods defined with empty parentheses, such as def height(): Int, are called empty-paren methods. The recommended convention is to use a parameterless method whenever there are no parameters and the method accesses mutable state only by reading fields of the containing object (in particular, it does not change mutable state). This convention supports the uniform access principle which says that client code should not be affected by a decision to implement an attribute as a field or method.

Processing in Scala!

One of the great things about scala is that it inter-operate with any existing Java library. Both ways, use scala classes from java and java from scala. Here’s an quick example of using Processing in Scala.

I’m using IntelliJ IDEA 9.0.1 with the Scala plugin.
To get Processing working in IntelliJ:

  1. Download the processing.org jars
  2. Create a Scala project.
  3. Add them to your libraries list in the modules setting.
  4. Create a new scala object example below.

How is this useful? Scala’s syntax and its core data structures allow processing of data in a much more concise and understandable manner. Imagine you want to visualize xml or csv files with the Processing/Scala combo. Scala makes this easy with its xml and string manipulation libraries.

This example code is from Ben Fry’s Visualizing Data Book

import processing.core._
object Draw extends processing.core.PApplet {

  override def setup() {
    size(200, 200)
    noStroke( )
    fill(0, 102, 153, 204)
  }

  override def draw() {
    background(255)
    rect(width-mouseX, height-mouseY, 50, 50)
    rect(mouseX, mouseY, 50, 50)
  }

  def main(args: Array[String]) {
    val frame = new javax.swing.JFrame("Draw")
    frame.getContentPane().add(Draw)
    Draw.init

    frame.pack
    frame.setVisible(true)
  }
}

Read Books on the Amazon Kindle 3