1

I have a list of method signatures of some trait T given as objects, similar to the following, ignoring arity:

case class Method[T,A,B](name: String, f: T => A => B)

So given some trait T, this could look like:

trait T{
  def foo(i: Int): String
  def bar(s: String): Unit
}

def methodsOfT: Seq[Method[T,_,_]] = Seq(
  Method("foo", t => i => t.foo(i)),
  Method("bar", t => s => t.bar(s))
)

I want to create an instance of type T, or of the class associated with T, whatever, that uses a dictionary of Method objects to implement T's interface.

It could look like the following (this won't compile):

def reify[T](impl: T, methods: Method[T,_,_]): T = (new Object with Dynamic {
  def applyDynamic(method: String)(args: Any*): Any = {
    //do something here
  }
}).asInstanceOf[T]  //<- will fail at runtime

Of course the returned object is of type Object, and cannot be cast to type/class T. Is there any way to work around this problem?

Why I want to do this

I have a trait T for which I want to create a remote invocation interface. On the client side, I need an instance of T that forwards method invocations over a network connection. I could implement this RemoteT. But the code is completely boilerplate.

new T {
  def foo(i: Int): String = 
    methodsOfT.find(_.name == "foo").get.f(i).asInstanceOf[String]
  def bar(s: String): Unit = 
    methodsOfT.find(_.name == "bar").get.f(s).asInstanceOf[Unit]
}

I think I could use macros to synthesize the method overrides and forward them to the network remote handler. But I'm still trying to avoid macros.

P.S.

The following question is very related. I'm currently exploring this approach: Java Reflection: Create an implementing class

ziggystar
  • 28,410
  • 9
  • 72
  • 124

1 Answers1

2

I believe similar thing is done in shapeless to implement lenses.

Here you can see that dynamics delegate creation of lens to an implicit - returned type is taken from functional depenencies (here: that mkLens.Out)

trait Lens[S, A] extends LPLens[S, A] { outer =>
...
  def selectDynamic(k: String)
    (implicit mkLens: MkSelectDynamicOptic[Lens[S, A], A, Symbol @@ k.type, Nothing]): mkLens.Out = mkLens(this)
...
}

the Lens itself is not generated with macro, but with normal derivation, but you can use macro to generate implicit, it should be possible.

object Generic1 extends Generic10 {
...

  implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] =
    macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[t, U] })#λ]

...
}

A combination of macro + dynamics is used in HList.

object HList extends Dynamic {
...
  /**
   * Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows,
   *
   * {{{
   * type ISB = HList.`Int, String, Boolean`.T
   * }}}
   *
   * Literal types are allowed, so that the following is valid,
   *
   * {{{
   * type ABC = HList.`'a, 'b, 'c`.T
   * type TwoTrueStr = HList.`2, true, "str"`.T
   * }}}
   */
  def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.hlistTypeImpl
...
}

All in all, you should be able to achieve you goal. It all just depends on how exactly you want to instantiate you object - e.g. take implicit ClassTag and call constructor using reflection or maybe constructing HList and using Generic to turn it into an specific representation or maybe some something else.

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64