import scala.language.dynamics import scala.reflect.{ ClassTag, classTag } object Util { def show[T](x: T): T = { println(x) ; x } def mkArgs(xs: Any*) = xs map { case ((k, v)) => k + "=" + v ; case x => "" + x } mkString ("(", ", ", ")") } import Util._ abstract class MonoDynamic extends Dynamic { def selectDynamic(name: String): String = show(this + "." + name) def applyDynamic(name: String)(args: Any*): String = show(this + "." + name + mkArgs(args: _*)) def applyDynamicNamed(name: String)(args: (String, Any)*): String = show(this + "." + name + mkArgs(args: _*)) override def toString = (this.getClass.getName split '.').last } object Mono extends MonoDynamic { def f(s: String): String = s def f1 = this.bar() def f2 = this.bar def f3 = f(this.bar()) def f4 = f(this.bar) def f5 = f(f(f(f(f(f(this.bar)))))) + f(f(f(f(f(f(this.baz)))))) def f6 = f(f(f(f(f(f(this.bar(bippy = 1, boppy = 2))))))) + f(f(f(f(f(f(this.baz)))))) } object Poly extends Dynamic { def selectDynamic[T: ClassTag](name: String): String = show(s"$this.$name[${classTag[T]}]") def applyDynamic[T: ClassTag](name: String)(args: Any*): String = show(args.mkString(s"$this.$name[${classTag[T]}](", ", ", ")")) def f(s: String): String = s def f1 = this.bar def f2 = this.bar[Int] def f3 = this.bar() def f4 = this.bar[Int]() def f5 = this.bar[Int](1, 2, 3) def f6 = f(f(this.bar)) def f7 = f(f(this.bar[Int])) def f8 = f(f(this.bar())) def f9 = f(f(this.bar[Int]())) def f10 = f(f(this.bar[Int](1, 2, 3))) override def toString = "Poly" } object Updating extends Dynamic { def selectDynamic(name: String): String = show(s"$this.$name") def updateDynamic(name: String)(value: Any): String = show(s"$this.$name = $value") def f1 = this.bar def f2 = this.bar = "b" override def toString = "Updating" } object Nest1 extends Dynamic { def applyDynamic(name: String)(args: Any*): Nest2.type = Nest2 object Nest2 extends Dynamic { def applyDynamicNamed(name: String)(args: (String, Any)*): Nest3.type = Nest3 object Nest3 extends MonoDynamic { } } def f1 = Nest1.bip().bop(foo = "bar").bippy(1, 2, 3) def f2 = Nest1.bip("abc").bop(foo = 5).bippy } object Named extends Dynamic { def applyDynamic(name: String)(args: Any*): Named.type = { show(this + "." + name + mkArgs(args: _*)) this } def applyDynamicNamed(name: String)(args: (String, Any)*): Named.type = { show(this + "." + name + mkArgs(args: _*)) this } def f1 = this.bippy(a = 1, b = 2).boppy(c = 3, d = 4)()()(e = 5, f = 6) override def toString = "Named" } object Named2 extends Dynamic { def applyDynamic(name: String)(a: Any)(b: Any = "b", c: Any = "c"): Named2.type = { show(this + "." + name + mkArgs(a) + mkArgs(b, c)) this } def applyDynamicNamed(name: String)(a: (String, Any))(b: (String, Any), c: (String, Any)): Named2.type = { show(this + "." + name + mkArgs(a) + mkArgs(b, c)) this } def f1 = this.bippy(1)(b = "q0") def f2 = this.bippy(1)("q0") def f3 = this.bippy(1)(c = "q0") def f4 = this.bippy(1)("q0") def f5 = this.bippy(1)(c = "b", b = "c") def f6 = this.bippy(1)("b", "c") def f7 = this.bippy(1)(b = "q0").bippy(2)() def f8 = this.bippy(1)("q0").bippy(5)(c = "c").dingus(100)(c = "dong") def f9 = this.bippy(1)(b = "q0", c = "q1").hello(100)("!!", "!!") override def toString = "Named2" } object Test { def main(args: Array[String]): Unit = { { import Mono._ f1 ; f2 ; f3 ; f4 ; f5 f6 } { import Poly._ f1 ; f2 ; f3 ; f4 ; f5 f6 ; f7 ; f8 ; f9 ; f10 } { import Updating._ f1 ; f2 } { import Nest1._ f1 ; f2 } { import Named._ f1 } { import Named2._ f1 ; f2 ; f3 ; f4 ; f5 f6 ; f7 ; f8 ; f9 } } }