generic trait taking a class and it's companion object as a type parameter

generics, scala

Solution

There's a bunch of problems in your code.. let's tackle it one after the other:

- `def table[T](...` note that this `T` overwrites the original type parameter for the scope of the method. Not what you want really, so just omit it and make this `def table(...`

- `object Controller with BaseCrud {` contains two more mistakes:

- it has to be `extends` not `with`. The latter is only used after you already extended from some base-class/trait.

- `BaseCrud` requires a type parameter that you have to specify here, so something like `BaseCrud[Customer]`

- and finally, to answer your actual question: There is a huge difference between a type parameter `T` and a companion object. They are inherently different things, so you cannot access the companion object via `T.something`. Instead you need to provide the companion object in your trait in some other way, for example as an abstract field.

Here's a version of what I believe you want to do:

abstract class BaseModel[T] {
  def all: Seq[T]
}

case class Customer(email: String, password: String)

object Customer extends BaseModel[Customer] {
  def all = List[Customer]() // have to define this
}

trait BaseCrud[T] {
  val companion : BaseModel[T]
  def table(f: T => String): String = {
    companion.all.map(f).mkString("")
  }
}

object Controller extends BaseCrud[Customer] {
  val companion = Customer
  def foo = table(_.email)
}

Problem

So I want to have a generic trait take as a type parameter a class with a companion object that inherits from a specific base class and refer to both the companion object and the class itself. So, ``` abstract class BaseModel[T] { def all: Seq[T] } case class Customer(email: String, password: String) object Customer extends BaseModel[Customer] // This trait is my issue trait BaseCrud[T] { def table[T](f: T => String): String = { T.all.map(f _).mkString("") } } object Controller with BaseCrud { def foo = table(_.email) } ``` I had some solutions to that trait that were closer but I distilled it down so you can see what I am trying to do. Thanks UPDATE So I went with solution from Frank below, but I did manage to solve my initial puzzle. Though, in this case the solution was a bit ugly I'll include it here for completeness sake. ``` abstract class BaseModel[T] { def all: Seq[T] = Seq() } case class Customer(email: String, password: String) object Customer extends BaseModel[Customer] trait BaseCrud[T, U <: BaseModel[T]] { def table(f: T => String)(implicit obj: U): String = { obj.all.map(f(_)).mkString("") } } object Controller extends BaseCrud[Customer, Customer.type] { implicit val model = Customer def foo = table(_.email) } ``` So the type parameters changed to BaseCrud and the implicit was added to BaseCrud.table and implemented in Controller.model. I also fixed all my typos. I found it interesting Customer.type seems to be the type of the companion object.

Original source

Related problems