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.