Skip to content

Instantly share code, notes, and snippets.

@bartschuller
Last active May 17, 2018 19:28
Show Gist options
  • Save bartschuller/4687387 to your computer and use it in GitHub Desktop.
Save bartschuller/4687387 to your computer and use it in GitHub Desktop.
Using Scala's Dynamic trait and reflection to implement delegation. If we swap reflection for macros it will be fast and typesafe again. I guess this could then replace the AutoProxy compiler plugin.
name := "delegation"
scalaVersion := "2.10.0"
libraryDependencies <+= (scalaVersion)("org.scala-lang" % "scala-reflect" % _)
import scala.language.dynamics
import reflect.ClassTag
import scala.reflect.runtime.universe._
trait Runner {
def runAway()
}
class Player extends Runner {
def runAway() {
println("Running away")
}
}
class Thrower[T <: Runner](val self: T) {
def throwBall() {
println("Ball thrown")
self.runAway()
}
}
object Main {
def main(args: Array[String]) {
val player = new Player with Delegate[Thrower[Player]]
player.delegate = new Thrower[Player](player)
player.throwBall()
}
}
// Naming it HasDelegate would be more correct, but this reads better:
// "with Delegate"
trait Delegate[T] extends Dynamic {
var delegate: T = _
import scala.reflect.runtime.{universe => ru}
def applyDynamic(method: String)(args: Any*)(implicit tTag: TypeTag[T], cTag: ClassTag[T]) = {
val m = ru.runtimeMirror(delegate.getClass.getClassLoader)
val sym = ru.typeTag[T].tpe.declaration(ru.newTermName(method)).asMethod
val im = m.reflect(delegate)
val methodMirror = im.reflectMethod(sym)
methodMirror.apply(args:_*)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment