I was trying to implement some Model - Row implementation similar that Rails (Activerecord) in Scala. I simply trying to do this;
trait Model[A]:
def query = "model has this good stuff I want to use in RowData"
trait RowData[B <: Model[B]]:
def query = B.query
case class Person(name: String, age: Int) extends RowData[Person]
object Person extends Model[Person]
Person("onur", 38).query // I wan't to use like this
I'm getting Not found: B on RowData
trait. Because Model[A]
is an object I supposed that I can use it as is.
You can try in here: https://scastie.scala-lang.org/U3MOJhFXSS2O8fanY5aIpg
CodePudding user response:
trait RowData[B <: Model[B]]:
def query = B.query
This is not supported because (among other reasons) the query
method might not exist.
The problem is that the type of the companion object is not related to the type of the class. So the fact that B
is a subclass of Model[B]
says nothing about the type of the companion object of B
. And specifically, it does not require the companion object of B
to be a subclass of Model[B]
and therefore it is not required to have the appropriate query
method.
The other problem is that this does not compile:
trait RowData[B <: Model[B]]:
def query = B.query
case class Person(name: String, age: Int) extends RowData[Person]
The RowData
trait requires that Person
is a subclass of Model[Person]
but Person
does not inherit from Model[Person]
You either need to have Person
inherit from Model
and provide the appropriate query
method, or look at using a type class for this problem.
CodePudding user response:
It seems the requirement is to use companion object's method, but the issue with this solution is that,
trait RowData[B <: Model[B]]:
def query = B.query
Because B
is supposed to be an Object, it cannot be passed as a type in []
. You need to pass it as an Object in a parenthesis ()
, like this
trait Model[A]:
def query = "model has this good stuff I want to use in RowData"
trait RowData(B: Model[_]):
def query = B.query
case class Person(name: String, age: Int) extends RowData(Person)
object Person extends Model[Person]
Person("onur", 38).query
However, this is not an ideal solution either, because B is not enforced to be the companion object you pass for the row data class. In Scala, we commonly use Context Bound to enforce this, like this:
trait Model[A]:
def query = "model has this good stuff I want to use in RowData"
trait RowData[B : Model]:
def query = summon[Model[B]].query
case class Person(name: String, age: Int) extends RowData[Person]
given Person: Model[Person] with {} //Implement custom query method here
Person("onur", 38).query