Quantcast

Val and Final

classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Val and Final

Lalit Pant
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Jamie Webb-2
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Alex Blewitt
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Jon Pretty
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.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Jamie Webb-2
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Jamie Webb-2
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Lalit Pant
> 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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Jamie Webb-2
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Lalit Pant
> 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


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [scala] Val and Final

Jamie Webb-2
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
Loading...