scalaread-eval-print-loopjavapscala-repl

Unable to use scala's repl :javap to look at trait companion object


I am using the :javap command in the scala repl and was trying to look at the traits companion object, but I couldn't seem to find out how. Here is what I do from command line.

$ cat > Foo.scala <<EOF
trait Foo {
  def foo: String
  def echo = println(foo)
}
EOF
$ scalac Foo.scala
$ javap Foo.class
Compiled from "Foo.scala"
public abstract class Foo$class {
  public static void echo(Foo);
  public static void $init$(Foo);
}
$ javap Foo\$class.class
Compiled from "Foo.scala"
public abstract class Foo$class {
  public static void echo(Foo);
  public static void $init$(Foo);
}

I try the same in the repl and get the following (using Bar since Foo will be compiled in ., so repl will pick it up)

scala> trait Bar {
     | def bar: String
     | def echo = println(bar)
     | }
defined trait Bar

scala> :javap Bar
Compiled from "<console>"
public interface Bar{
    public abstract java.lang.String bar();
    public abstract void echo();
}


scala> :javap Bar$class
Failed: Could not find class bytes for 'Bar$class'

Scala version of repl

$ scala -version
Scala code runner version 2.10.2 -- Copyright 2002-2013, LAMP/EPFL

Running on a mac

EDIT: Just downloaded scala 2.11 and ran the repl there. It seems that :javap is able to pick up the class, but its running :javap -v rather than :javap. Switching to :javap -p makes this output the same as 2.10


Solution

  • You're not asking about the companion module, but about the trait implementation class.

    Not finding class bytes was a bug in 2.10, fixed in 2.11.

    If you do have a companion object, currently you must use its encoded name, such as Bar$.

    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    trait Bar { def bar: Int }
    object Bar { def apply() = new Bar { def bar = 8 } }
    
    // Exiting paste mode, now interpreting.
    
    defined trait Bar
    defined object Bar
    
    scala> :javap -prv Bar$
    Binary file Bar$ contains $line3.$read$$iw$$iw$Bar$
      Size 701 bytes
      MD5 checksum a46d3c3cb62cb5ed3521a697023e82dd
      Compiled from "<console>"
    public class $line3.$read$$iw$$iw$Bar$
    [snip]
    

    For your impl class example, I think you're asking for:

    scala> :javap -public x.Foo$class
    Compiled from "x.scala"
    public abstract class x.Foo$class {
      public static void echo(x.Foo);
      public static void $init$(x.Foo);
    }
    

    Note:

    scala> :javap -help
    usage       :javap [opts] [path or class or -]...
    -help       Prints this help message
    -raw        Don't unmangle REPL names
    -app        Show the DelayedInit body of Apps
    -fun        Show anonfuns for class or Class#method
    -verbose/-v Stack size, number of locals, method args
    -private/-p Private classes and members
    -package    Package-private classes and members
    -protected  Protected classes and members
    -public     Public classes and members
    -l          Line and local variable tables
    -c          Disassembled code
    -s          Internal type signatures
    -sysinfo    System info of class
    -constants  Static final constants
    

    and

    val DefaultOptions = List("-protected", "-verbose")
    

    The help menu could say more about using the term Bar instead of the type; there may be a forthcoming -demo that shows various usages.

    I was going to joke about it using the reflection API -- :javap TermName("Bar") -- but maybe that's not a joke.