ItemsList on 2.8 and initialization order

1 view
Skip to first unread message

Naftoli Gugenheim

unread,
Jun 3, 2010, 8:02:37 PM6/3/10
to liftweb, Scala User List
First, apologies for cross-posting.

I noticed recently that in Lift, part of the ItemsList test were commented out for 2.8 because it was failing tests, so I looked into why it was failing.
It seems to be an issue with initialization order. Was this changed in 2.8? Where can I find out more information?

Here's the culprit:

trait ItemsList[T <: MetaMapper[T]]{
  ...
  def metaMapper: T with MetaMapper[T]
  ...
  def reload {
    refresh
    ...
  }
  def refresh {
    current = metaMapper.findAll
  }
  ...
  reload
}

So 'refresh', which is called on instantiation, assumes 'metaMapper' has been initialized.
However, in ItemsListSpecs the following code

    new ItemsList[SampleItem] {
      val metaMapper = SampleItem
    }

throws a NullPointerException: at the time refresh is called metaMapper has in fact not been instantiated, apparently.

There are a few simple solutions but I'd first like some reference or background on this change.


Thanks.

Naftoli Gugenheim

unread,
Jun 8, 2010, 4:08:36 PM6/8/10
to Jason Zaugg, liftweb, Scala User List
I'm confused - is this SID implemented yet or not?


On Fri, Jun 4, 2010 at 1:45 AM, Jason Zaugg <jza...@gmail.com> wrote:
This SID [1] outlines the motivations for the changed semantics.

When upgrading a codebase from 2.7, use -Xwarninit to warn about the
changed semantics:

 ~: scala -Xwarninit -e 'trait B { val b: Int; println(b) }; new B {
val b = 1 }'
 warning: the semantics of this definition has changed;
the initialization is no longer be executed before the superclass is called

You can also use -Xcheckinit to get a precise runtime error when
reference an uninitlialized fields. This has a small performance
penalty, similar to lazy vals. I'd recommend to use this in your test
suite only.

  ~: scala -Xcheckinit -e 'trait B { val b: Int; println(b) }; new B
{ val b = 1 }'
 scala.UninitializedFieldError: Uninitialized field: (virtual file): 6
       at Main$$anon$2$$anon$1.b((virtual file):6)

While you're at it, add -deprecation -Xmigration to the options.

What are the solutions? You can make the field lazy, or use Early Defintion:

new {
  val metaMapper = SampleItem
} with ItemsList[SampleItem]

I've found this doesn't work with trait initialization [2], beware.

-jason

[1] http://www.scala-lang.org/sid/4
[2] http://lampsvn.epfl.ch/trac/scala/ticket/2796

Naftoli Gugenheim

unread,
Jun 14, 2010, 7:55:01 PM6/14/10
to liftweb
So I'm wondering which of two possible solutions I should go with.

The simple solution is to replace the val metaMapper definition in ItemsListSpecs with a def. Similarly, anyone using 2.8 will have to obey the new rules and use a def rather than a val.

The more complex solution would be to remove the call to reload in the class body, and instead use a private 'inited' flag, calling reload the first time anything relevant is accessed.

What do people think?
Reply all
Reply to author
Forward
0 new messages