vendredi 23 septembre 2016

Scala Design using reflection, implicit and generics

I have different sources and corresponding parameters

Source1, Source2, Source3

Parameter1, Parameter2, Parameter3,

Source: is trait (can be changed)

trait Source[T] {
 def get(Parameter)(implicit c: Context): MyData[T]
}

Parameter is also a trait

trait Parameter

I have different OutputType class: T1, T2, T3

I need output as: MyData[OutputType]

Fixed API signature (changes to the signature not quite preferable):

val data1: MyData[T1] = MyAPI.get[T1](Parameter1("a", "b")) // this should give MyData from Source1 of type T1
val data2: MyData[T2] = MyAPI.get[T2](Parameter3(123)) // this should give MyData from Source3 of type T2

Some source supports some output types (say T1, T2), but some may not.

What I did: I tried using scala reflection typeTag to determine the type at runtime, but since return type will be MyData[T], and is in contra-variant position, it wont know the actual return type. (Why does TypeTag not work for return types?) e.g.

object MyAPI {
  get[T: TypeTag](p: Parameter)(implicit c: Context): MyData[T] = {}
}

I also tried using type-class pattern. Scala TypeTag Reflection returning type T I can work with different OutputType creating implicit val for each, but would only work for single Source1. I can't manage to work for all sources.

I was trying to do:

    object MyAPI {
      get[T: SomeConverter](p: Parameter)(implicit c: Context): MyData[T] = {
         p match {
          case Parameter1 => Source1[T].read(p.asInstanceOf(Parameter1)
          case Parameter2 => Source2[T].read(p.asInstanceOf(Parameter2)
         }
       }
    }

Aucun commentaire:

Enregistrer un commentaire