Something Similar

About Jeff Hodges
Atom Feed

Tricky Things in Scala-land

I’ve got an old document here describing some of the tricky things and gotchas I found while learning Scala (and some things I had to be reminded of about the JVM) and trying to build on top of Hadoop. I’ve turned that document into this blog post. A few things only apply to Scala 2.7, but thems the breaks.

  • Inner classes (as in the Foo class has an inner Bar class) are accessed as Foo#Bar. You can avoid writing those every with a type MyBar = Foo#Bar in the class or object that’s using the inner class.

  • Getting the class while in the class definition portion of your code is not via Foo.class but classOf[Foo].

  • <%, the view bound operator, lets you accept a container with objects inside that may obey a another trait. The not-exactly-correct meaning of its use is “only allow types that can be turned into this another type”. For instance, I once wanted a min method to implicitly exist on Array. For the method to compile, it had to only accept Arrays that contained types that could be wrapped in Orderable. Using <%in the type parameter of the method made this possible. Of course, this turned out to be a moot point when I found the static (that is, object) method Iterable.min in Scala 2.7. In Scala 2.8, min is nicely defined on types that are Iterables. Also, please ignore how terrible that one-liner min method is.

  • Oh, yeah, by the way, Iterable.min exists in Scala 2.7. Would have saved me learning more about the Scala type system than I really cared to at that point.

  • If you get an “integer too large” when putting in a raw number (like when trying val l = 0xc6a4a7935bd1e995), you forgot the ‘L’. As in, val l = 0xc6a4a7935bd1e995L. This is hopefully the dumbest thing I had to figure out on this list.

  • To define a method or constructor that takes a subclass as it’s argument, you have to use a view bound, <%, to ensure the type of the class. Say, for instance, you want to construct a subclass of Hadoop’s ArrayWritable which requires a class to be passed to it that is a subclass of Writable. To do that you would write:

    class MyArrayWritable(klass: java.lang.Class[_ <: Writable]) extends ArrayWritable(klass) { }

  • Because of the difference between how Scala and Java look up inner classes, when attempting to work with a Java classes that passes its type parameters to its inner classes, you’ll have to use the type trick and a shim class to work with it properly. For instance, Hadoop’s Mapper class required me to do this:

    class SMapper[A,B,C,D] extends Mapper[A,B,C,D] { type Context = Mapper[A,B,C,D]#Context }

  • The default constuctors syntax is odd. The error message (“error: wrong number of arguments for constructor”) is clearer to to someone who knows Scala because of the little arrow pointing at the supertype in question but it caused me some consternation and javadoc hunting before realizing, no, I wasn’t wrong about the type of my superclass, and, instead, just forgot the syntax for default constructors. You just have to pass your constructor args to the superclass in the extends line. So, given the code below, the important part is to pass bar in to Mine as Mine(bar) in that extends line.

    class Ours(bar: Int) extends Mine(bar) { }

  • Here’s a small list of methods that are useful when trying to explore your way around a library in the Scala REPL.

    val c = new C val clazz = c.getClass val clazz2 = classOf[C] val methods = clazz.getMethods val ctors = clazz.getConstructors val fields = clazz.getFields val annos = clazz.getAnnotations val name = clazz.getName val parentInterfaces = clazz.getInterfaces val superClass = clazz.getSuperclass val typeParams = clazz.getTypeParameters

  • Use javap to figure out what methods are actually on an instance of your class. This is often useful to figure out why your method isn’t overriding a method in its superclass.

  • Also, when using javap, don’t forget that Scala objects have a $ added to the end of their name, so double check the names of the actual class files.

  • When using javap, your shell will probably require the $ to be escaped (as \$) or have single quotes around it to parse your input properly. e.g. javap -c 'Outer$Inner'.

  • Oh, and adding -private and -verbose to your javap arguments is how you find out anything really useful.