Paweł Kaczorowski
Paweł Kaczorowski

Reputation: 1562

Scala Implicit class and inheritance

let's say that I would like to add some method to String class. But concrete implicit class that should be applied is known during runtime (strategy pattern). Lets say we have

trait StringExtensions {
  def doSth(str: String): String
}

class Strategy1 extends StringExtensions {
   override def doSth(str: String): String = "a"
}

class Strategy2 extends StringExtensions {
   override def doSth(str: String): String = "b"
}

now my client code looks like:

def someMethod(strategy: StringExtensions) : String{
  val name = "Pawel"
  return strategy.doSth(name)
}
...
String ret = someMethod(new Strategy1())

but I would like to have code like:

def someMethod(strategy: StringExtensions) : String{
  val name = "Pawel"
  return name.doSth() // Here is the tricky line
}
...
String ret = someMethod(new Strategy1())

I played a bit with implicits but when comes to this use case with inheritance I cannot find proper solution, any help?

Upvotes: 4

Views: 1624

Answers (1)

Jasper-M
Jasper-M

Reputation: 15086

I'm not sure you should really use implicits like this, but maybe in some DSL this might be a valid use case.

class StringExtensions(str: String, strategy: StringExtensionsStrategy) {
  def doSth() = strategy.doSth(str)
}

trait StringExtensionsStrategy extends (String => StringExtensions) {
  final def apply(str: String) = new StringExtensions(str, this)
  def doSth(str: String): String
}

class Strategy1 extends StringExtensionsStrategy {
   override def doSth(str: String) = "a"
}

class Strategy2 extends StringExtensionsStrategy {
   override def doSth(str: String) = "b"
}

def someMethod(implicit strategy: StringExtensionsStrategy) = {
  val name = "Pawel"
  name.doSth()
}

val ret: String = someMethod(new Strategy1())

As mentioned in the comments, an alternative encoding would be this:

class StringExtensions(str: String, strategy: StringExtensionsStrategy) {
  def doSth() = strategy.doSth(str)
}

trait StringExtensionsStrategy {
  implicit final def apply(str: String) = new StringExtensions(str, this)
  def doSth(str: String): String
}

class Strategy1 extends StringExtensionsStrategy {
   override def doSth(str: String) = "a"
}

class Strategy2 extends StringExtensionsStrategy {
   override def doSth(str: String) = "b"
}

def someMethod(strategy: StringExtensionsStrategy) = {
  import strategy._
  val name = "Pawel"
  name.doSth()
}

val ret: String = someMethod(new Strategy1())

Upvotes: 5

Related Questions