Scala cake pattern with Existential Types: compile error

182 views Asked by At

Through this question, I found this article on the 'config' pattern from Precog. I tried this with two modules:

case class Pet(val name: String)

trait ConfigComponent {
  type Config

  def config: Config
}

trait Vet {
  def vaccinate(pet: Pet) = {
    println("Vaccinate:" + pet)
  }
}


trait AnotherModule extends ConfigComponent {
  type Config <: AnotherConfig

  def getLastName(): String

  trait AnotherConfig {
    val lastName: String
  }

}

trait AnotherModuleImpl extends AnotherModule {
  override def getLastName(): String = config.lastName

  trait AnotherConfig {
    val lastName: String
  }

}

trait PetStoreModule extends ConfigComponent {
  type Config <: PetStoreConfig

  def sell(pet: Pet): Unit

  trait PetStoreConfig {
    val vet: Vet
    val name: String
  }

}

trait PetStoreModuleImpl extends PetStoreModule {
  override def sell(pet: Pet) {
    println(config.name)
    config.vet.vaccinate(pet)
    // do some other stuff
  }
}

class MyApp extends PetStoreModuleImpl with AnotherModuleImpl {

  type Config = PetStoreConfig with AnotherConfig

  override object config extends PetStoreConfig with AnotherConfig {
    val vet = new Vet {}
    val name = "MyPetStore"
    val lastName = "MyLastName"
  }

  sell(new Pet("Fido"))
}


object Main {
  def main(args: Array[String]) {
    new MyApp
  }
}

However, I get this compile errror:

overriding type Config in trait AnotherModule with bounds <: MyApp.this.AnotherConfig;
type Config has incompatible type
type Config = PetStoreConfig with AnotherConfig

It is not clear to me why this should not work (Precog also uses two components in their example), any ideas?

2

There are 2 answers

2
rarry On BEST ANSWER

Remove definition of AnotherConfig from AnotherModuleImpl

1
Shadowlands On

You define AnotherConfig twice - once in AnotherModule, and again in AnotherModuleImpl. These two definitions of the trait are different, and are considered incompatible. The type Config is defined in terms of the former of these, but when you define MyApp, you are setting the type to the latter - hence the error.

You can fix it by either removing the latter definition of AnotherConfig (as suggested by @rarry) or having the latter trait extend the former (if you have some reason to keep the latter, such as defining extra fields).