1

This is one of my early attempts at implementing a Scala Cake Pattern:

trait dbConfig {
  val m: Model = ???
}

trait testDB extends dbConfig {
  override val m = new Model(Database.forURL("jdbc:h2:mem:testdb", driver = "org.h2.Driver"))
  m.cleanDB
}

trait productionDB extends dbConfig {
  override val m = new Model(Database.forURL("jdbc:postgresql:silly:productionDB", driver = "org.postgresql.Driver"))
}

trait SillySystem extends HttpService with dbConfig {
....
// System logic
....
}

This will allow me to use my service like this while testing:

class TestService extends SillySystem with testDB {
.....
}

And like this for production:

class ProductionService extends SillySystem with productionDB {
.....
}

This works, but am I doing it correctly?

Jack
  • 16,506
  • 19
  • 100
  • 167
  • 1
    You can leave the `m` member abstract in the trait `val m: Model`, and there's no need to `override` in the subtrait – pagoda_5b Nov 10 '12 at 12:31

1 Answers1

3

It could be helpful to make DbConfig abstract and use def since one can override a def with a val or lazy val, but not the other way round.

SillySystem is not a DbConfig, so use dependency injection instead of inheritance.

trait DbConfig {
  def m: Model // abstract
}

trait TestDB extends DbConfig {
  // you can override def with val
  val m = new Model(Database.forURL("jdbc:h2:mem:testdb", driver = "org.h2.Driver"))
  m.cleanDB
}

trait ProductionDB extends DbConfig {
  val m = new Model(Database.forURL("jdbc:postgresql:silly:productionDB", driver = "org.postgresql.Driver"))
}

trait SillySystem extends HttpService {
  this: DbConfig => // self-type. SillySystem is not a DbConfig, but it can use methods of DbConfig.
....
// System logic
....
}

val testService = new SillySystem with TestDB

val productionService = new SillySystem with ProductionDB

val wrongService1 = new SillySystem // error: trait SillySystem is abstract; cannot be instantiated
val wrongService2 = new SillySystem with DbConfig // error: object creation impossible, since method m in trait DbConfig of type => Model is not defined

val correctService = new SillySystem with DbConfig { val m = new Model(...) } // correct
Community
  • 1
  • 1
senia
  • 37,745
  • 4
  • 88
  • 129
  • You sir, are my hero! You addressed exactly the two things that I didn't like about my early attempt. I did not know a about the def's that could be overridden with vals, and I knew I needed a typed self reference, but I was unsure how to use it. Thanks! – Jack Nov 10 '12 at 12:51
  • self types are not free, however, there's a price to pay in compile time (read: probably best not to go nuts, sprinkling "self: Foo with Bar with Baz" => all over the place) – virtualeyes Nov 10 '12 at 20:28