Search code examples
scalamixinsimplicit-conversionself-type

Scala using Implicit with Self Types


I have a implicit class which requires a user database. I want to use self-type in implicit class so I can switch implementation of database in testing scope to the mocked version. How do I mix-in database provider in this case? For example, I want user of RuchUser to not worry about having to mix-in UserDatabaseProvider by providing default mix-in. So user can just do User("name").userContext and do the same at testing scope where I will provide default mix-in to use mocked database provider?

case class User(name: String)

object User {
  implicit class RichUser(self: User) { this: UserDatabaseProvider =>
     def userContext: String = this.getUserContext(self.name)
  }
}

// Usage of Rich user should be below as I want to provide already mixed-in implicit
import User._
val context = User("name").uerContext

Solution

  • I think you are overcomplicating quite a bit.

    case class User(name: String) {
      def context()(implicit db: UserDatabaseProvider): UserContext = {
        db.getUserContext(name)
      }
    }
    

    I would go to further suggest the cake pattern may be more applicable here than using implicits.

    class UserService extends UserDatabaseProvider {
      def context(user: User): UserContext = getUserContext(user.name)
    }
    class TestUserService extends UserService with TestDatabase
    

    Let "right-most wins" diamond resolution in Scala do the job for you.