2

I am using several classes like this:

class MyClassOne {
  doSomething(a : A) : B
  ... 
} 

class MyClassTwo {
  doSomething(a : A) : B
  ... 
} 

The source for the classes is not under my control. Although the classes have methods with the same signature they don't implement an interface. I would like to define methods that work on all the classes.

So I've made a Trait like this:

trait MyTrait {
  doSomething(a : A) : B
}

And have made implicit conversions for all the classes:

implicit class MyClassOneMyTrait(myClassOne : MyClassOne) {
  def doSomething(a : A) = myClassOne.doSomething(a)
}

Is there a way to take advantage of the naming conventions used in the classes and avoid explicitly delegating to the objects passed into the constructor? More generally, is using a Trait with implicit classes the best approach to this problem?

mushroom
  • 6,201
  • 5
  • 36
  • 63

1 Answers1

4

Actually, there is scala feature exactly for your situation. It's called structural types.

For structural types type requirements are expressed by interface structure instead of a concrete type. Internal implementation uses reflection, so be performance-aware!
type A = String
type B = String

class MyClassOne {
  def doSomething(a: A): B = {
    println("1")
    "1"
  }
}

class MyClassTwo {
  def doSomething(a: A): B = {
    println("2")
    "2"
  }
}

type MyClassType = {
  def doSomething(a: A): B
}

List[MyClassType](new MyClassOne, new MyClassTwo).foreach(_.doSomething("test"))
List(new MyClassOne, new MyClassTwo).foreach {
  case a: MyClassType => a.doSomething("test")
  case _ =>
}
Aivean
  • 10,692
  • 25
  • 39
  • What would be your second choice if you wanted to avoid the performance penalty of reflection? – mushroom Sep 23 '15 at 01:12
  • @mushroom Using [Adapter](https://en.wikipedia.org/wiki/Adapter_pattern) design pattern. Actually, your original approach is one way to implement it. – Aivean Sep 23 '15 at 01:39