|
It looks like vals do not get translated to final fields by the Scala compiler.
Final fields, of course, have significant benefits on the JVM: - they have special semantics under the Java Memory model, and allow immutable objects to be freely published and shared without synchronization (http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.5) - they give compilers a lot of room for optimization Given that vals are not re-assignable (just like finals are not), it seems like mapping vals to final fields would work out really well. But that is not how Scala implements them. Any ideas why? The following scala code: package p1 class ValFinal { val aVal = 10 } compiles to the following java class: $ javap -private ValFinal Compiled from "ValFinal.scala" public class p1.ValFinal extends java.lang.Object implements scala.ScalaObject{ private int aVal; public p1.ValFinal(); public int aVal(); public int $tag(); } Thanks, - Lalit PS. I saw many discussions on the list skirting around this question, but did not find a definitive answer to this anywhere. |
|
On 2007-10-22 17:33:21 Lalit Pant wrote:
> Given that vals are not re-assignable (just like finals are not), it > seems like mapping vals to final fields would work out really well. > But that is not how Scala implements them. Any ideas why? Because val members may be overridden, unless declared final. /J |
|
On 23/10/2007, Jamie Webb <[hidden email]> wrote:
> > Because val members may be overridden, unless declared final. But in Scala, a val member is overriden by creating a subclass with a new method 'aVal()', right? There's no reason that the private member could not also be final (in bytecode), and yet still allow subclasses to override the val from above. Alex. |
|
Alex Blewitt wrote:
> On 23/10/2007, Jamie Webb <[hidden email]> wrote: >> Because val members may be overridden, unless declared final. > > But in Scala, a val member is overriden by creating a subclass with a > new method 'aVal()', right? There's no reason that the private member > could not also be final (in bytecode), and yet still allow subclasses > to override the val from above. Vals not marked as final might not be final; they may change in later versions. The sort of optimisations that Latit mentions (inlining and sharing) would make changing a (final) val horrendously difficult, possibly meaning recompiling all your code, plus any dependencies it might have anywhere in the world. That's really not feasible. For this reason, having a field fixed for all eternity should be a necessary - and not just sufficient - condition for it to be marked 'final'. Jon -- Jon Pretty | Sygneca Ltd. |
|
On 2007-10-23 13:41:14 Jon Pretty wrote:
> Alex Blewitt wrote: > > On 23/10/2007, Jamie Webb <[hidden email]> wrote: > >> Because val members may be overridden, unless declared final. > > > > But in Scala, a val member is overriden by creating a subclass with > > a new method 'aVal()', right? There's no reason that the private > > member could not also be final (in bytecode), and yet still allow > > subclasses to override the val from above. > > Vals not marked as final might not be final; they may change in later > versions. The sort of optimisations that Latit mentions (inlining and > sharing) would make changing a (final) val horrendously difficult, > possibly meaning recompiling all your code, plus any dependencies it > might have anywhere in the world. That's really not feasible. > > For this reason, having a field fixed for all eternity should be a > necessary - and not just sufficient - condition for it to be marked > 'final'. No, this does not apply to Scala. Compile-time inlining is done only for static final fields, and Scala does not emit static fields (or non-private ones for that matter). /J |
|
In reply to this post by Alex Blewitt
On 2007-10-23 08:34:47 Alex Blewitt wrote:
> On 23/10/2007, Jamie Webb <[hidden email]> wrote: > > > > Because val members may be overridden, unless declared final. > > But in Scala, a val member is overriden by creating a subclass with a > new method 'aVal()', right? There's no reason that the private member > could not also be final (in bytecode), and yet still allow subclasses > to override the val from above. Yes, you're quite right. Ok, another attempt: consider how vals defined in traits are initialised. /J |
|
> Yes, you're quite right. Ok, another attempt: consider how vals defined
> in traits are initialised. Hmmm... trait T1 { val aVal = 10 } class C1 extends T1 { } translates to: public interface T1 extends ScalaObject { public abstract int aVal(); public abstract void aVal_$eq(int i); } public abstract class T1$class { public static void $init$(T1 $this) { $this.aVal_$eq(10); } } public class C1 implements T1, ScalaObject { private int aVal; public C1() { T1$class.$init$(this); } public final void aVal_$eq(int x$1) { aVal = x$1; } public final int aVal() { return aVal; } <snip> } This will not work (as I think you wanted to point out) if aVal is translated to a final field in C1. But - since vals in traits cannot be extended, C1 can potentially work correctly if it is translated to: public class C1 implements T1, ScalaObject { public C1() { } public final int aVal() { return 10; } } That is: vals in traits can get translated to getter methods (on classes implementing the trait) that return literals. So - it still seems like vals can get translated to final fields (with the corresponding getter not being final)? - Lalit |
|
On 2007-10-23 18:01:32 Lalit Pant wrote:
> But - since vals in traits cannot be extended, C1 can potentially work > correctly if it is translated to: > > public class C1 > implements T1, ScalaObject { > > public C1() { > } > > public final int aVal() { > return 10; > } > } > > That is: vals in traits can get translated to getter methods (on > classes implementing the trait) that return literals. But that only works if the val is defined to be a literal, which is not an interesting case. In general, the val can be assigned as part of an arbitrarily complex constructor. /J |
|
> But that only works if the val is defined to be a literal, which is not
> an interesting case. In general, the val can be assigned as part of an > arbitrarily complex constructor. Ok, Cool. That makes sense... How about constructor args? Is there a reason for them to not be final fields? The argument for vals to be not final (relating to how they are initialized in traits) does not seem to apply for constructor args. - Lalit |
|
On 2007-10-24 06:43:07 Lalit Pant wrote:
> > > But that only works if the val is defined to be a literal, which is > > not an interesting case. In general, the val can be assigned as > > part of an arbitrarily complex constructor. > > Ok, Cool. That makes sense... > > How about constructor args? Is there a reason for them to not be final > fields? The argument for vals to be not final (relating to how they > are initialized in traits) does not seem to apply for constructor > args. Yes, I see no reason why they could not be final, other than possibly for consistency. /J |
| Powered by Nabble | Edit this page |
