Search code examples
scalacake-pattern

Cake Pattern: How to share an instance?


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?


Solution

  • 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