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 innerBar
class) are accessed asFoo#Bar
. You can avoid writing those every with atype 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
butclassOf[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 amin
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) methodIterable.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-linermin
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’sArrayWritable
which requires a class to be passed to it that is a subclass ofWritable
. 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 passbar
in toMine
asMine(bar)
in thatextends
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
object
s have a$
added to the end of their name, so double check the names of the actualclass
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.