Dear all,
How can I get the val
s and var
s in my object
s to compile into fields as pieces of bytecode? scalac (2.11) by default represents them as methods – I gathered using javap. Is there any way I can instruct it to do as I like instead? Any scalac command-line parameters? Code annotations?
TIA,
–Hossein
Do you mean public fields? Then I don’t think it’s possible. The only things that get compiled to (private) fields without methods are private[this]
vals and vars.
As a matter of fact, I don’t quite know what it is that I should be looking for. My request here on this list comes from my conversation on another (Scala-unrelated) list. And, I am being almost verbatim. Here is an example for what I think was meant. Consider this code:
object O {
val f = 0.0
}
When I javap O.class and O$.class, I get
public final class O {
public static double f();
}
and
public final class O$ {
public static final O$ MODULE$;
public static {};
public double f();
}
in both of which there is no mention of f
except as methods. (And, it’s even worse if I make it private[this]
because f
completely vanishes then.) How can I get f
to be a field in O.class or O$.class?
TIA,
–Hossein
It will be a field in almost all cases. You have to call javap -p to see private fields and methods.
Here is my Aha moment: So, Scala fields do get compiled into bytecode fields – albeit private
. It only is that the public
Scala ones also get the getter/setter pair of methods, whereas the rest don’t. Is that right?
And, what are the exceptions?
I think final val a = 42
becomes
public final int a() {
return 42;
}
I’m not 100% sure.
That’s right. A public val gets a public accessor, and a public var gets a public accessor and public mutator. But they’re both backed by a private field.
Private vals and vars also get the methods but then they’re private as well. Private[this] is the exception, those only get a private field.
It makes sense too. If you compile
object O {
val f = 0.0
}
to the equivalent of
public final class O {
public static double f;
}
rather than
public final class O {
private static double f;
public static double f(){ return f;}
}
you have a public field that can be expected to be mutated.Since f is a val
, you wouldn’t expect that to be possible.
Now if it were a var
, I can’t see any direct reason why it needs accessors rather than expose the bare field - though that’s primarily a statement about me rather than about the implementation.
Interestingly (at least to me) the field is only used by its accessor for as far as I can see. Having another member access f
in the object itself goes through the accessor as well. I wouldn’t be able to tell whether that introduces inefficiencies in jitted code (it at least seems like something the JVM would be good at optimizing, since it’s such a common pattern in Java), what the consequences on binary compatibility are.
Lastly, the really weird one to me is
object O {
final val a = 1.2
}
which produces
scala> :javap -c -p -constants O
Compiled from "<console>"
public class O$ {
public static final O$ MODULE$;
private final double f;
public static {};
Code:
0: new #2 // class O$
3: invokespecial #12 // Method "<init>":()V
6: return
public final double f();
Code:
0: ldc2_w #16 // double 1.2d
3: dreturn
public O$();
Code:
0: aload_0
1: invokespecial #19 // Method java/lang/Object."<init>":()V
4: aload_0
5: putstatic #21 // Field MODULE$:LO$;
8: return
}
Getting f
still goes through the accessor, but the accessor returns a constant rather than the field f, which is never read from at all - which is a good thing too, since it doesn’t get initialized either(!).