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.
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:
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]
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With