4

I came across the following code snippet on the Scala mailing list:

scala> class DynamicImpl(x: AnyRef) extends Dynamic {
     |   def _select_(name: String): DynamicImpl = {
     |     new DynamicImpl(x.getClass.getMethod(name).invoke(x))
     |   }
     |   def _invoke_(name: String)(args: Any*) = {
     |     new DynamicImpl(x.getClass.getMethod(name, args.map(_.asInstanceOf[AnyRef].getClass) : _*).invoke(x, args.map(_.asInstanceOf[AnyRef]) : _*))
     |   }
     |   override def typed[T] = x.asInstanceOf[T]
     |   override def toString = "Dynamic(" + x.toString + ")"
     | }
defined class DynamicImpl

scala> 

scala> implicit def toDynamic(x: Any): Dynamic = new DynamicImpl(x.asInstanceOf[AnyRef])
toDynamic: (x: Any)Dynamic

scala> class Duck {
     |   def quack = "Quack!"
     | }
defined class Duck

scala> class QuackingSwan {
     |   def quack = "Swack!"
     | }
defined class QuackingSwan

scala> def makeQuack(d: Dynamic) {
     |   println(d.quack.typed[String])
     | }
dynatype: d._select_("quack")
makeQuack: (d: Dynamic)Unit

scala> makeQuack(new Duck)
Quack!

scala> makeQuack(new QuackingSwan)
Swack!

scala> val s: Dynamic = "Hello, world!"
s: Dynamic = Dynamic(Hello, world!)

scala> s.toLowerCase
dynatype: line8$object.$iw.$iw.s._select_("toLowerCase")
res2: Dynamic = Dynamic(hello, world!)

scala> s.length
dynatype: line8$object.$iw.$iw.s._select_("length")
res3: Dynamic = Dynamic(13)

scala> s.isEmpty.typed[Boolean]
dynatype: line8$object.$iw.$iw.s._select_("isEmpty")
res4: Boolean = false

What's _select_ and _invoke_ here?

missingfaktor
  • 90,905
  • 62
  • 285
  • 365

1 Answers1

1

_select_ and _invoke_ behave like Ruby missing_method. When any method is called on a dynamic instance which does not implement the method, _select_ or _invoke_ are called instead. Those two methods can be implemented as you wish.

In your example, they use reflection to call the an actual implementation of the x member. For instance:

scala> val s: Dynamic = "Hello, world!"
s: Dynamic = Dynamic(Hello, world!)

scala> s.toLowerCase
dynatype: line8$object.$iw.$iw.s._select_("toLowerCase")
res2: Dynamic = Dynamic(hello, world!)

The method toLowerCase is not defined in s. So the method _select_ is called instead with argument "toLowerCase". The dynamic mechanism will then call x.toLowerCase using reflection and wrap the result in a new dynamic instance.

_select_ is called for any method without arguments, while _invoke_ is called for any method with arguments.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • 1
    If `_invoke_` is Scala's `method_missing`, what is `applyDynamic` then? – missingfaktor Jul 21 '11 at 12:50
  • 1
    Two important things:The Dynamic trait has no methods, it is a marker trait: http://www.scala-lang.org/api/current/index.html#scala.Dynamic. The dynamic feature is still experimental and must be activated by calling scala with the -Xexperimental option. – Christian Jul 21 '11 at 12:51
  • I was confused by that: http://www.assembla.com/code/scala-eclipse-toolchain/git/nodes/src/library/scala/Dynamic.scala?rev=e8607b971718f2b33db74ba9071d825c24885c62 But apparently it's not on Scala code. – paradigmatic Jul 21 '11 at 13:14
  • After going thru some threads on mailing list, it seems all methods in `Dynamic` trait were removed. I wonder why. – missingfaktor Jul 21 '11 at 13:45
  • I am accepting this answer as I don't see anything better coming. – missingfaktor Jul 25 '11 at 22:55
  • 1
    Please see http://stackoverflow.com/questions/5185459/dynamic-proxy-using-scalas-new-dynamic-type about the newer version of Dynamic. – Blaisorblade Oct 09 '11 at 12:51