Scala: Mis-using traits, gives runtime error (fixing typo in other post)

56 views
Skip to first unread message

Brent Gracey

unread,
May 25, 2015, 5:42:39 AM5/25/15
to scala...@googlegroups.com

Sorry for the broad topic; I'm just not quite sure what I'm doing wrong.

I have a class structure

trait BaseType {
  val property: String
}

trait MiddleTrait extends BaseType {
  val myProperty = property.length.toString
  def userProperty() = {
    myProperty
  }
}

object Top extends MiddleTrait {
  val property = "value given here"
}    trait BaseType {
  val property: String
}

Which compiles; but hits a run time error - java.lang.RuntimeException: java.lang.NoClassDefFoundError: Could not initialize class controllers.test.Top$

Updating MiddleTrait to **def** myProperty = property.length.toString it will run fine.

I looking to understand the theory behind this better so I could predict the error without seeing it fail at run time first

Thanks

Martin Mauch

unread,
May 25, 2015, 6:17:21 AM5/25/15
to scala...@googlegroups.com
Hi Brent,

I think you're running into problems caused by "early initializers":

If you change the val to a def, then myProperty becomes lazy and will be called after the superclass fields have been initialized.

Best
  Martin

Jon Pretty

unread,
May 25, 2015, 7:08:36 AM5/25/15
to Martin Mauch, scala-user
Hi Brent,

Just to elaborate on Martin's answer, the problem is that the body of `Top`, which contains the concrete implementation of `val property` is evaluated *after* the body of `MiddleTrait` which eagerly evaluates `val myProperty`, whose body depends on `property`, and we can see, deterministically, that it will always fail because these two values need to be evaluated in the reverse order.

You can "fix" this by ensuring that `property` is initialized *before* the body of MiddleTrait by writing `Top` as follows:

   object Top extends { val property = "value given here" } with MiddleTrait

This feature of Scala is called "early initializers" (they're the name of the *solution*, rather than the problem - though arguably the name could refer to the problem too...), but they are normally best avoided, which you can usually do with more careful inheritance, or using `def`s (as you found out) or `lazy val`s (which don't result in the re-evaluation of the implementation every time it's accessed). Dotty will not have early initializers.

Cheers,
Jon

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Jon Pretty | @propensive

Som Snytt

unread,
May 25, 2015, 1:04:29 PM5/25/15
to Brent Gracey, scala-user
It's been a while since we heard from the Urfaq, formerly known as the One-question faq.

http://docs.scala-lang.org/tutorials/FAQ/initialization-order.html

On local access cable tv they're still running ads for -Xcheckinit.

$ scala -Xcheckinit

scala> Top.myProperty
scala.UninitializedFieldError: Uninitialized field: <console>: 19
  at Top$.property(<console>:19)
  at MiddleTrait$class.$init$(<console>:12)
  ... 35 elided



--

Jon Pretty

unread,
May 25, 2015, 4:22:06 PM5/25/15
to Som Snytt, Brent Gracey, scala-user
On 25 May 2015 at 18:04, Som Snytt <som....@gmail.com> wrote:
It's been a while since we heard from the Urfaq,

​It's been a couple of weeks since I've replied to anything here. I thought you were talking about me.​
 
On local access cable tv they're still running ads for -Xcheckinit.

​I should tune in more often.​

Cheers,
Jon

Brent Gracey

unread,
May 25, 2015, 4:54:32 PM5/25/15
to scala...@googlegroups.com
Great; thanks for all the info

Naftoli Gugenheim

unread,
May 26, 2015, 6:34:52 PM5/26/15
to Jon Pretty, Martin Mauch, scala-user


On Mon, May 25, 2015, 7:08 AM Jon Pretty <prope...@gmail.com> wrote:

Hi Brent,

Just to elaborate on Martin's answer, the problem is that the body of `Top`, which contains the concrete implementation of `val property` is evaluated *after* the body of `MiddleTrait` which eagerly evaluates `val myProperty`, whose body depends on `property`, and we can see, deterministically, that it will always fail because these two values need to be evaluated in the reverse order.

You can "fix" this by ensuring that `property` is initialized *before* the body of MiddleTrait by writing `Top` as follows:

   object Top extends { val property = "value given here" } with MiddleTrait

This feature of Scala is called "early initializers" (they're the name of the *solution*, rather than the problem - though arguably the name could refer to the problem too...), but they are normally best avoided, which you can usually do with more careful inheritance, or using `def`s (as you found out) or `lazy val`s (which don't result in the re-evaluation of the implementation every time it's accessed). Dotty will not have early initializers.


...since it will give traits value parameters, which avoid the problem, no?

Jon Pretty

unread,
May 28, 2015, 1:13:22 PM5/28/15
to Naftoli Gugenheim, Martin Mauch, scala-user
On 26 May 2015 at 23:34, Naftoli Gugenheim <nafto...@gmail.com> wrote:

...since it will give traits value parameters, which avoid the problem, no?


​That's the plan, I believe.

Cheers,
Jon

Reply all
Reply to author
Forward
0 new messages