Scala compiles to JVM bytecode, which is the same compilation target as Java. Unless the decompiler targets Scala explicitly, decompiling to Java makes sense.
To complement the information in Alexey Romanov's answer, which is still current and valid for Scala 2, I'd like to add that since Scala 3 (a.k.a. Dotty, its development name), Scala first compiles to an intermediate representation, TASTy (which adds Typed Abstract Syntax tree information to the compiled classfiles -- hence the name).
You can see an presentation about TASTy and its role in the compiler pipeline in this interesting talk at Scala Days 2019.
As mentioned in the talk, Dotty natively offers the possibility of decompiling the compilation output (TASTy + classfiles).
As a simple experiment, let's consider this very simple program in a file Main.scala
:
object Main {
def main(args: Array[String]): Unit = {
println("hello, world")
}
}
Running dotc Main.scala
on it produces the expected output (a .class
file for the Main
class, one for the Main
object and a .tasty
file), which can be fed back into the (de)compiler with the -decompile
option, as follows:
dotc -decompile Main
The output of this command is the following:
/** Decompiled from ./Main.tasty */
@scala.annotation.internal.SourceFile("Main.scala") object Main {
def main(args: scala.Array[scala.Predef.String]): scala.Unit = scala.Predef.println("hello, world")
}
You can follow the instructions here to get started with Dotty and perform the same experiment as I did, which was run with Dotty 0.27.0-RC1.