3

I have a configuration component in my Scala project.

Obviously I don't want to have more than one instance of this component. I'm using the cake pattern, but I'm not sure how to tweak it to fit my requirements:

// Library
// =================================================
trait ConfigComp {

  trait Config {
    def get(k: String): String
  }

  def config: Config
}

trait QueueComp {
  self: ConfigComp =>

  class Queue {
    val key = config.get("some-key")
  }

  lazy val queue = new Queue
}

// Application
// =================================================

trait MyConfig extends ConfigComp {

  lazy val config = new Config {
    println("INITIALIZING CONFIG")

    def get(k: String) = "value"
  }
}

object Frontend extends QueueComp with MyConfig
object Backend  extends QueueComp with MyConfig

Frontend.queue.key
Backend.queue.key

prints:

INITIALIZING CONFIG
INITIALIZING CONFIG

How to make the cake pattern share the anonymous instance of Config?

stephanos
  • 3,319
  • 7
  • 33
  • 47
  • 2
    If you want something to be shared between classes (i.e. something that exists in only one exemplar), put it in object and access object value from this trait that will be mixed in. – om-nom-nom Feb 01 '13 at 19:52
  • Thanks, I tried that and am stuck with an "has incompatible type"-error: https://gist.github.com/4693853 – stephanos Feb 01 '13 at 20:27
  • 1
    see comment below your snippet. I still wait if somebody could explain "has incompatible type" error, but as a temporary workaround this should work well. – om-nom-nom Feb 01 '13 at 20:42
  • 1
    in your gist, you can make the nested trait work by changing `def config: Config` to `def config: ConfigComp#Config`. Look for scala's path-dependent types (for instance look at this question: http://stackoverflow.com/questions/2183954/referring-to-the-type-of-an-inner-class-in-scala ). – Paolo Falabella Feb 02 '13 at 23:32

2 Answers2

3

Something like this ?

// Library
// =================================================
trait Config {
  def get(k: String): String
}

trait ConfigComp {
  def config: Config
}

trait QueueComp {
  self: ConfigComp =>
  class Queue {
    val key = config.get("some-key")
  }
  lazy val queue = new Queue
}

// Application
// =================================================

object SingleConfig extends ConfigComp {
  lazy val config = new Config {
    println("INITIALIZING CONFIG")
    def get(k: String) = "value"
  }
}

object Frontend extends QueueComp with ConfigComp {
  val config = SingleConfig.config
}
object Backend  extends QueueComp with ConfigComp {
  val config = SingleConfig.config
}

Frontend.queue.key
Backend.queue.key

If your Config trait is placed inside ConfigComp, I could not workaround these type errors:

error: type mismatch;
 found   : MyConfig.Config
 required: Frontend.Config
    (which expands to)  Frontend.Config
                override def config = MyConfig.config

error: type mismatch;
 found   : MyConfig.Config
 required: Backend.Config
    (which expands to)  Backend.Config
                override def config = MyConfig.config
idonnie
  • 1,703
  • 12
  • 11
1

As om-nom-nom mentioned, you're looking to use a singleton, and thus should make MyConfig use a config that is initialized in an object. To the second question, in your gist, the following error:

[error] overriding method config in trait ConfigComp of type => MyConfig.this.Config;
[error]  lazy value config has incompatible type
[error]   lazy val config = MyConfig.config
[error]            ^
[error] one error found

essentially tells you exactly the problem. MyConfig.this.Config is not equal to the object MyConfig.this.Config. To make it more clear, let's change the code to the following:

object MyConfigSingleton extends ConfigComp {
  val config = new Config {
    println("INITIALIZING CONFIG")
    def get(k: String) = "value"
  }
}

trait MyConfig extends ConfigComp {
  lazy val config = MyConfigSingleton.config
}

Here, the type MyConfig.this.Config != MyConfigSingleton.this.Config

Alex DiCarlo
  • 4,851
  • 18
  • 34
  • thanks for the explanation! -it seems like there is no solution where `Config` is nested inside of `ConfigComp`, is there? It's probably bad design anyway ;-) – stephanos Feb 01 '13 at 22:30