Bubble Foundry


Introduction to Case Classes

by Peter.

I’ve been recently chatting with the creator of match-js about how his library and caseclass.js might work together and I ended up writting quite a bit about case classes. Enjoy.

Scala is a newish object-oriented/functional hybrid language that runs on the JVM. It actually takes a lot of concepts from Erlang, such as its actor library. One of its key features is pattern matching, which at the most basic can be used to test equality. With the match operator that means you have something like switch/case in most languages:

val myVal = 3;
myVal match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case _ => "other"
} // returns "three"

Case classes at a glance are just simple classes that be created without the new operator and automatic getters and setters:

case class Person(name, age)
val peter = Person("Peter Robinett", 25)
peter.age == 25 // -> true

However, you can do a lot more advanced stuff:

unknownVar match {
  case n: String => println("unknowVar is a String with value: " + n)
  case n: Int if n > 0 => println("unknownVar is an Int with a value greater than 0")
  case Person(name, 100) => println("unknownVar is a Person case class where property age is 100 and name is: " + name)
}

The last case example shows a cool use of a case class. Scala knows that when a case class instance is created in a case, you are testing for matching. So, it calls the class’s unapply method (any class can have one, case classes just have them automatically) to compare the instance based upon its properties. If the parameters match, the two instances are equal. However, you can also not specify properties to match. If you don’t care about them all you can just give a wildcard (the _ character) or not give any parameters (case Person or case person: Person) but if you’d like to extract the value, you can. This is what I did. By giving it the undefined variable ‘name’, it knows that I am not comparing the name properties but instead want to assign unknownVar.name to name (assuming that unknownVar is an instance of Person!), which is then within the scope of the subsequent code block.

So, that’s a lot of Scala. What do I have in Javascript? Right now you can match based upon object types:

CaseClass.create("Person", ["name", "age"]);
var peter = CaseClass.Person("Peter Robinett", 25);
peter.match(
  {
    caseTest: "Car",
    caseFunction: function() { return 0; }
  },
  {
    caseTest: CaseClass.Person,
    caseFunction function() { return 1; }
  }
); // -> return 1 – I'm not a Car!

Parameter definition and extraction also works, though it’s limited:

var undef;
peter.match(
  {
    caseTest: CaseClass.Person("Barack Obama", 47),
    caseFunction: function() { return 0; }
  },
  {
    caseTest: CaseClass.Person("Peter Robinett", undef),
    caseFunction function() { return age; }
  }
); // -> return 25

As you can see, matching works fine though I need pass an uninitialized variable to Person() to indicate that I want to extract the corresponding property in peter. Because I cannot discover the name of this variable, I just have to create variables based upon the property names. I’d like to improve this, but the consensus seems to be that it’s impossible with Javascript today (ironically, earlier versions could). Beyond extractors, I’d like to be able to do more complex matching (better support for different object types, conditional stations) and be able to extend native objects to support my matching. I also like that your Match() method can stand alone, letting it be used as a callback and meaning that it acts as a sort of partial function, which is very cool. In Scala partial functions are functions that needn’t always return a value:

def myPF(num: Int) = {
  case 1 => "one"
  case -1 => "negative one"
}

To be honest, I’m not sure if our libraries could or should work together but they’re similar enough in spirit that I thought it might be exploring how they can complement each other. I see you’re doing stuff with web workers. I’ve also tried to take Scala’s actors and use them to do something in Javascript. actor.js is the result and is a place where I think case classes would be great for message passing (this is a key use case for case classes in Scala). However, actors are both more complex and something that I have less experience with, so I haven’t put as much time into it as caseclass.js. However, the demo does work and is, in my opinion, pretty cool!