Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala cake-pattern compile error with Precog config pattern

Following from this question, I have now the following:

case class Pet(val name: String)

trait ConfigComponent {
  type Config

  def config: Config
}

trait VetModule extends ConfigComponent {
  type Config <: VetModuleConfig

  def vet: Vet

  trait Vet {
    def vaccinate(pet: Pet)
  }

  trait VetModuleConfig {
    def extra: String
  }

}

trait VetModuleImpl extends VetModule {
  override def vet: Vet = VetImpl

  object VetImpl extends Vet {
    def vaccinate(pet: Pet) = println("Vaccinate:" + pet + " " + config.extra)
  }

}

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 PetStoreModule extends ConfigComponent {
  type Config <: PetStoreConfig

  def petStore: PetStore

  trait PetStore {
    def sell(pet: Pet): Unit
  }

  trait PetStoreConfig {
    val petStoreName: String
  }

}

trait PetStoreModuleImpl extends PetStoreModule {
  self: VetModule with AnotherModule =>
  override def petStore: PetStore = PetstoreImpl

  object PetstoreImpl extends PetStore {
    def sell(pet: Pet) {
      vet.vaccinate(pet)
      println(s"Sold $pet! [Store: ${config.petStoreName}, lastName: $getLastName]")
    }
  }
}

class MyApp extends PetStoreModuleImpl with VetModuleImpl with AnotherModuleImpl {

  type Config = PetStoreConfig with AnotherConfig

  override object config extends PetStoreConfig with AnotherConfig {
    val petStoreName = "MyPetStore"
    val lastName = "MyLastName"
  }

  petStore.sell(new Pet("Fido"))
}


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

I get the following compile error:

value petStoreName is not a member of PetStoreModuleImpl.this.Config
     println(s"Sold $pet! [Store: ${config.petStoreName}, lastName: $getLastName]")
                                   ^

This is actually the error I have been struggling with. Can somebody explain why it occurs? Currently, as a work-around, I just explicitly cast the config object in each module implementation.

like image 206
damirv Avatar asked Jan 12 '23 14:01

damirv


1 Answers

What you've written should work, but doesn't, because of this bug.

There are a number of workarounds you could use. Adding type Config = PetStoreConfig with AnotherConfig to your module implementation is probably a little less unpleasant than casting.

Update: As som-snytt notes in a comment and answer, adding with PetStoreModuleImpl (crucially not with PetStoreModule, as you might expect) to the end of the self-type is a better solution.

As a footnote: as discussed in the comments on SI-7255, the Dependent Object Types calculus (which is designed to be "a new foundation for Scala's type system") will address this "fundamental problem in Scala's type system".

like image 73
Travis Brown Avatar answered Jan 31 '23 09:01

Travis Brown