How are final val defined inside a trait treated by Scala Compiler?

1.3k views Asked by At

I use very often the selfless trait pattern and I need to use "expensive" constants inside the trait: I would like to have a single instance of these values, which might require several steps to be computed, in all my application.

However, the selfless trait pattern results in the following design:

  • A trait MyStuff
  • An object MyStuff extends MyStuff

Clearly, putting constants inside the object and using them inside a trait creates a cyclic dependency. Putting them on the trait however , makes possible for all the classes extending the trait to override them, and therefore they are certainly not an application-wide singleton.

Is the Scala compiler "clever enough" to makes final vals inside a trait become "old java public static final" ?

3

There are 3 answers

0
som-snytt On

What's an example of the cyclic dependency you're concerned about?

Usually that's solved through appropriate use of defs in the trait or lazy vals.

Here's an example issue that is induced by default args (which are synthesized in the companion object).

But if you need eagerness, you can always define early, définition en avance:

scala> :pa
// Entering paste mode (ctrl-D to finish)

trait Foo {
  val v = 2 * Foo.w
}
object Foo extends {
  private val w = 3
} with Foo

// Exiting paste mode, now interpreting.

defined trait Foo
defined object Foo

scala> Foo.v
res11: Int = 6

If calculating w uses members of Foo, though, you'd have to go lazy:

trait Foo {
  val v = 2 * Foo.w
  def x = 7
}
object Foo extends Foo {
  lazy val w = 3 * x
}

This is the second time today I've needed the one-question FAQ, but I haven't looked for its new home yet.

(Edit: why, here it is.)

0
senia On

As analogue of public static final you should use a companion object like this:

trait MyStuff
object MyStuff {
 val publicStaticFinal = ...
}

In this case scalac creates a singleton object (public static final MyStuff$ MODULE$) with method public int publicStaticFinal(). You could make this method final if you want to.

For public final - use final val:

trait MyStuff
 final val publicFinal = ...
}

In this case scalac creates an interface with public abstract int publicFinal() and implements it in every ancestor of MyStuff as public final int publicFinal().

1
Paolo Falabella On

No, scala will not translate a final val inside a trait to the equivalent of a java static final, because the final val will need to be an instance member (not a static member) of the inheriting class.

scala> trait myStuff { final val Test="test" }
defined trait myStuff

scala> class t extends myStuff
defined class t

scala> t.Test
<console>:8: error: not found: value t
              t.Test
              ^

// we need an instance of t to access Test
scala> new t
res2: t = t@35612600

scala> res2.Test
res3: String = test

if you're using selfless trait and you can't store your final val in MyStuff's companion object (because you're using it in the trait itself), you could probably just create another object for your final val.

//your expensive constant is here
scala> object MyConstant {final val C="C"}
defined module MyConstant

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait MyStuff {
import MyConstant._
def doStuff = C
}
object MyStuff extends MyStuff

// Exiting paste mode, now interpreting.

defined trait MyStuff
defined module MyStuff

// let's test importing the companion object of the selfless trait 
scala> import MyStuff._
import MyStuff._

scala> doStuff
res4: String = C