Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am getting frustrated because I don't know how to handle the frontier between my typesafe code and the external API which uses polymorphism and inheritance.

My flow is the following. I receive an entry value of class Class1, which I use to retrieve from an external service an item of Class Class2. Then I need to subtype on both to obtain the runtime type of them and resolve the implicit. However, this is not possible because of type erasure.

trait Typeclass1[A, B] {
  def hash(a: A, b: B): String
}

trait Typeclass2[A, B] {
  def hash(a: A, b: B): B
}

trait Entity

trait MyEntity1

trait MyEntity2

object db {
  def load(any:Any):Entity = new Entity{}
}


class MyClass[T](t: T, a: String) {

  def apply(timeout: Long): T = {
    val loadFromDB = db.load(t)
    loadFromDB match {
      case myEntity1: MyEntity1 => applyTypeSafe(myEntity1)
      case myEntity2: MyEntity2 => applyTypeSafe(myEntity2)
    }
  }


  def applyTypeSafe[C](c: C)(implicit typeClass1: Typeclass1[C, T], typeclass2: Typeclass2[C, T]): (String, T) = {
    typeClass1.hash(c, t) -> typeclass2.hash(c, t)
  }
}

I am wondering what is the right pattern to develop this frontier layer. I would probably need a type-constructor for my typeclass to provide at at the constructor of MyClass... or maybe to totally rethinkg my design?

share|improve this question
I do not see the problem. Which types get erased? As far as I can see you should be able to pattern match reliably on loadFromDB and then you have recovered all the type info the DB layer looses. – gzm0 17 hours ago

1 Answer

There is no compilation issue if you add implicit definitions in scope for MyEntity and MyEntity2. For example, the code below compiles ok:

trait Typeclass1[A, B] { def hash(a: A, b: B): String }
trait Typeclass2[A, B] { def hash(a: A, b: B): B }

trait Entity
trait MyEntity1 extends Entity
trait MyEntity2 extends Entity

object db { def load(any:Any):Entity = new Entity {} }

implicit def MyEntity1HasTypeclass1[T] = new Typeclass1[MyEntity1, T] {
  def hash(a: MyEntity1, t: T) = a.toString
}
implicit def MyEntity1HasTypeclass2[T] = new Typeclass2[MyEntity1, T] {
  def hash(a: MyEntity1, t: T) =t
}

class MyClass[T](t: T, a: String) {
  def apply(timeout: Long): (String, T) = {
    db.load(t) match {
      case myEntity1: MyEntity1 => applyTypeSafe(myEntity1)
    }
  }
  def applyTypeSafe[C](c: C)(implicit typeClass1: Typeclass1[C, T], 
                                      typeclass2: Typeclass2[C, T]): (String, T) = {
    typeClass1.hash(c, t) -> typeclass2.hash(c, t)
  }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.