Search code examples
scalaobjectgenericstraitsscala-3

How to use an Object in a trait by using its type in Scala


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


Solution

  • It seems the requirement is to use the companion object's method, but the issue with this solution is that, given this code:

    trait RowData[B <: Model[B]]:
      def query = B.query
    

    Because B is supposed to be the companion object, it cannot be passed as a type in []. You need to pass it as an object in parentheses (), 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 RowData trait. 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