I've been working with Scala for a while now and have written a 10,000+ line program with it, but I'm still confused by some of the inner workings. I came to Scala from Python after already having intimate familiarity with Java, C and Lisp, but even so it's been slow going, and a huge problem is the frustrating difficulty I've often found when trying to investigate the inner workings of objects/types/classes/etc. using the Scala REPL as compared with Python. In Python you can investigate any object foo
(type, object in a global variable, built-in function, etc.) using foo
to see what the thing evaluates to, type(foo)
to show its type, dir(foo)
to tell you the methods you can call on it, and help(foo)
to get the built-in documentation. You can even do things like help("re")
to find out the documentation on the package named re
(which holds regular-expression objects and methods), even though there isn't an object associated with it.
In Scala, you can try and read the documentation online, go look up the source code to the library, etc., but this can often be very difficult for things where you don't know where or even what they are (and it's often a big chunk to bite off, given the voluminous type hierarchy) -- stuff is floating around in various places (package scala
, Predef
, various implicit conversions, symbols like ::
that are nearly impossible to Google). The REPL should be the way to explore directly, but in reality, things are far more mysterious. Say that I've seen a reference to foo
somewhere, but I have no idea what it is. There's apparently no such thing as a "guide to systematically investigating Scala thingies with the REPL", but the following is what I've pieced together after a great deal of trial and error:
- If
foo
is a value (which presumably includes things stored in variables plus companion objects and other Scalaobject
s), you can evaluatefoo
directly. This ought to tell you the type and value of the result. Sometimes the result is helpful, sometimes not. - If
foo
is a value, you can use:type foo
to get its type. (Not necessarily enlightening.) If you use this on a function call, you get the type of the return value, without calling the function. - If
foo
is a value, you can usefoo.getClass
to get its class. (Often more enlightening than the previous, but how does an object's class differ from its type?) - For a class
foo
, you can useclassOf[foo]
, although it's not obvious what the result means. - Theoretically, you can use
:javap foo
to disassemble a class -- which should be the most useful of all, but fails entirely and uniformly for me. - Sometimes you have to piece things together from error messages.
Example of failure using :javap
:
scala> :javap List
Failed: Could not find class bytes for 'List'
Example of enlightening error message:
scala> assert
<console>:8: error: ambiguous reference to overloaded definition,
both method assert in object Predef of type (assertion: Boolean, message: => Any)Unit
and method assert in object Predef of type (assertion: Boolean)Unit
match expected type ?
assert
^
OK, now let's try a simple example.
scala> 5
res63: Int = 5
scala> :type 5
Int
scala> 5.getClass
res64: java.lang.Class[Int] = int
Simple enough ...
Now, let's try some real cases, where it's not so obvious:
scala> Predef
res65: type = scala.Predef$@3cd41115
scala> :type Predef
type
scala> Predef.getClass
res66: java.lang.Class[_ <: object Predef] = class scala.Predef$
What does this mean? Why is the type of Predef
simply type
, whereas the class is scala.Predef$
? I gather that the $ is the way that companion objects are shoehorned into Java ... but Scala docs on Google tell me that Predef
is object Predef extends LowPriorityImplicits
-- how can I deduce this from the REPL? And how can I look into what's in it?
OK, let's try another confusing thing:
scala> `::`
res77: collection.immutable.::.type = ::
scala> :type `::`
collection.immutable.::.type
scala> `::`.getClass
res79: java.lang.Class[_ <: object scala.collection.immutable.::] = class scala.collection.immutable.$colon$colon$
scala> classOf[`::`]
<console>:8: error: type :: takes type parameters
classOf[`::`]
^
scala> classOf[`::`[Int]]
res81: java.lang.Class[::[Int]] = class scala.collection.immutable.$colon$colon
OK, this left me hopelessly confused, and eventually I had to go read the source code to make sense of this all.
So, my questions are:
- What's the recommended best way from the true Scala experts of using the REPL to make sense of Scala objects, classes, methods, etc., or at least investigate them as best as can be done from the REPL?
- How do I get
:javap
working from the REPL for built-in stuff? (Shouldn't it work by default?)
Thanks for any enlightenment.
showRaw
that was added shortly after M4 was released (and will appear in M5 tomorrow). It lets one inspect internal structure of some reflection artifacts (including trees and types). – Reisch