Initialization weirdness

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Initialization weirdness

Jesper Nordenberg
I found some weird behavior in this code:

    trait TestT {
     println("TestT1: " + x)
     val x = 10
     println("TestT2: " + x)
   }

   class TestC extends TestT {
     println("TestC1: " + x)   // Comment out this line
     override val x = 1
     println("TestC2: " + x)
   }

   val c = new TestC

It outputs:

TestT1: 0
TestT2: 10
TestC1: 10
TestC2: 1

Commenting out "println("TestC1: " + x)" gives this output:

TestT1: 1
TestT2: 10
TestC2: 10

All pretty confusing to me. Now let's try changing 'x' to a lazy val:

TestT1: 0
TestT2: 0
TestC1: 0
TestC2: 1

Commenting out "println("TestC1: " + x)":

TestT1: 1
TestT2: 1
TestC2: 1

Doh! Changing 'x' to a method makes the code work consistently.

Is the behavior of initialization code like this undefined in Scala?
What's the point of allowing it in that case?

/Jesper Nordenberg

Reply | Threaded
Open this post in threaded view
|

Re: Initialization weirdness

Martin Odersky
On Fri, Jun 20, 2008 at 11:19 AM, Jesper Nordenberg <[hidden email]> wrote:

> I found some weird behavior in this code:
>
>   trait TestT {
>    println("TestT1: " + x)
>    val x = 10
>    println("TestT2: " + x)
>  }
>
>  class TestC extends TestT {
>    println("TestC1: " + x)   // Comment out this line
>    override val x = 1
>    println("TestC2: " + x)
>  }
>
>  val c = new TestC
>
> It outputs:
>
> TestT1: 0
> TestT2: 10
> TestC1: 10
> TestC2: 1
>
> Commenting out "println("TestC1: " + x)" gives this output:
>
> TestT1: 1
> TestT2: 10
> TestC2: 10
>
> All pretty confusing to me. Now let's try changing 'x' to a lazy val:
>
> TestT1: 0
> TestT2: 0
> TestC1: 0
> TestC2: 1
>
> Commenting out "println("TestC1: " + x)":
>
> TestT1: 1
> TestT2: 1
> TestC2: 1
>
> Doh! Changing 'x' to a method makes the code work consistently.
>
> Is the behavior of initialization code like this undefined in Scala?
> What's the point of allowing it in that case?
>
It's a feature/bug which we still have to close. Before Scala had
pre-initialized fields, the compiler
moved a leading val definition which did not refer to `this' in front
of the superclass constructor call. That was very useful for some
common patterns of component plumbing (in fact these patterns are used
widely in the Scala compiler itself). But the feature is surprising to
the user, and very fragile. Pre-initialized fields were introduced as
a more disciplined way to achieve the same effect. It's just that we
still have to remove the old feature from the compiler.

Cheers

 -- Martin
Reply | Threaded
Open this post in threaded view
|

Re: Initialization weirdness

Jesper Nordenberg
martin odersky wrote:
> It's a feature/bug which we still have to close. Before Scala had
> pre-initialized fields, the compiler
> moved a leading val definition which did not refer to `this' in front
> of the superclass constructor call. That was very useful for some
> common patterns of component plumbing (in fact these patterns are used
> widely in the Scala compiler itself). But the feature is surprising to
> the user, and very fragile. Pre-initialized fields were introduced as
> a more disciplined way to achieve the same effect. It's just that we
> still have to remove the old feature from the compiler.

Thanks. Will the behavior of fields then be consistent with that of
methods (which always returns the overridden value)? Which Scala version
is this modification planned for?

/Jesper Nordenberg

Reply | Threaded
Open this post in threaded view
|

Re: Re: Initialization weirdness

Martin Odersky
On Fri, Jun 20, 2008 at 12:51 PM, Jesper Nordenberg <[hidden email]> wrote:

> martin odersky wrote:
>>
>> It's a feature/bug which we still have to close. Before Scala had
>> pre-initialized fields, the compiler
>> moved a leading val definition which did not refer to `this' in front
>> of the superclass constructor call. That was very useful for some
>> common patterns of component plumbing (in fact these patterns are used
>> widely in the Scala compiler itself). But the feature is surprising to
>> the user, and very fragile. Pre-initialized fields were introduced as
>> a more disciplined way to achieve the same effect. It's just that we
>> still have to remove the old feature from the compiler.
>
> Thanks. Will the behavior of fields then be consistent with that of methods
> (which always returns the overridden value)? Which Scala version is this
> modification planned for?

The behavior of fields will be as if you always had written the
println as first statement. I am working on the fix right now (thats
fior reminding me that it still needed to be done!)

Cheers

 -- Martin
Reply | Threaded
Open this post in threaded view
|

Re: Re: Initialization weirdness

Aaron Harnly-2-2
Thanks for asking about this, Jesper.

On Jun 20, 2008, at 7:10 AM, martin odersky wrote:

> On Fri, Jun 20, 2008 at 12:51 PM, Jesper Nordenberg <[hidden email]
> > wrote:
>>
>> Thanks. Will the behavior of fields then be consistent with that of  
>> methods
>> (which always returns the overridden value)? Which Scala version is  
>> this
>> modification planned for?
>
> The behavior of fields will be as if you always had written the
> println as first statement. I am working on the fix right now (thats
> fior reminding me that it still needed to be done!)

I very often resort to using defs for simple String and Int trait  
members for just this reason -- I've been bit so many times by weird  
behavior with vals that I just can't be bothered. Glad to know the  
inconsistencies will be ironed out.

~aaron