opus111
opus111

Reputation: 2844

Initializing values in Traits

I have an enormous class that I want to break in many traits. Each part of my class has a set of vals not used by the other parts. These parameters are read from a property file, sometimes with some calculation. I would like to have each trait be responsible for initializing its own variables. I would like these values to be private to the trait. Unfortunately, traits do not have constructors (which is what I really want).

What is the pattern for creating an object that mixes a set of traits, where the traits have values that need initializing?

Here is an example:

class Foo( properties: Properties ) extends Bar with Baz

trait Bar {
 private val something
}

trait Baz {
 private val somethingElse
}

How do I initialize Bar.something and Baz.somethingElse without either making them abstract and non-private, or adding an init() method and making them vars?

Thank you Peter

Upvotes: 3

Views: 1960

Answers (4)

opus111
opus111

Reputation: 2844

Here is a slight cleaner way that I finally used

class Foo( val propertyFile: String ) extends Bar with Baz with Zot

trait Bar extends Properties {
  private val something = getProperty("Something")
}

trait Baz extends Properties {
  private val somethingElse = getProperty("SomethingElse")
}

trait Zot extends Properties {
  private val somethingWeird = getProperty("Something") + getProperty("SomethingElse")
}

trait Properties {
  val propertyFile: String
  private val properties = readProperties(propertyFile)
  protected def getProperty(name: String) = properties.get(name)
}

Upvotes: 0

asthasr
asthasr

Reputation: 9397

What about early initialization?

trait A {
  val f: String
  val a = "I would have used " + f
}

trait B {
  val f: String
  val b = "I would have used " + f + " too!"
}

class C extends { val f = "the string" } with A with B

If you throw this into a REPL:

scala> List(c.a, c.b).map(println _)
I would have used the string
I would have used the string too!

Upvotes: 4

Rex Kerr
Rex Kerr

Reputation: 167871

You can just do the computation right there. Here's an example.

def readPropertyFile(s: String) = {
  println("Pretending to read " + s); 0
}

trait Bar {
  private val something = readPropertyFile("Bar.properties")
}

class Foo extends Bar {
  println("Hi, I am in class Foo")
}

scala> val foo = new Foo
Pretending to read Bar.properties
Hi, I am in class Foo
foo: Foo = Foo@27d8f985

As long as your resources are global, you can get at them easily. If not, mix them in in an earlier trait.

Upvotes: 1

opus111
opus111

Reputation: 2844

OK, here's one way. Is there something better?

class Foo( val properties: Properties ) extends Bar with Baz

trait Bar {
  val properties: Properties
  private val something = properties.get("Something")
}

trait Baz {
  val properties: Properties
  private val somethingElse = properties.get("SomethingElse")
}

Upvotes: 1

Related Questions