dynamic semantics

95 views
Skip to first unread message

Paul Phillips

unread,
May 3, 2012, 7:40:03 PM5/3/12
to scala-l...@googlegroups.com
Is it expected that you can't do anything with Dynamic unless the
methods have been implemented? Seems to defeat some of the purpose.
It "worked" in 2.9.2 at least for the definition of worked that
involves crashing. But you could see it was trying to work.

% scala292 -Xexperimental
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM,
Java 1.6.0_31).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def f(x: Dynamic) = x.bippy
dynatype: x.applyDynamic("bippy")()
dynatype: x.applyDynamic("applyDynamic")
dynatype: x.applyDynamic("applyDynamic")
dynatype: x.applyDynamic("applyDynamic")
dynatype: x.applyDynamic("applyDynamic")
dynatype: x.applyDynamic("applyDynamic")
dynatype: x.applyDynamic("applyDynamic")

% m3scala
Welcome to Scala version 2.10.0-M3 (Java HotSpot(TM) 64-Bit Server VM,
Java 1.6.0_31).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import language.dynamics
import language.dynamics

scala> def f(x: Dynamic) = x.bippy
<console>:8: error: value selectDynamic is not a member of Dynamic
def f(x: Dynamic) = x.bippy
^

scala> class Bippy extends Dynamic { def selectDynamic(name: String) =
println("I'm bippy!") }
defined class Bippy

scala> def f(x: Bippy) = x.bippy
f: (x: Bippy)Unit

scala> f(new Bippy)
I'm bippy!

Paul Phillips

unread,
May 3, 2012, 7:57:32 PM5/3/12
to scala-l...@googlegroups.com
And if it's intentional, how about we also offer something like this.
If for no other reason, so people don't have to read the signatures
out of documentation. Documentation can be wrong... like it is right
now.

// current documentation
* foo.arr(10) ~~> foo.applyDynamics("arr")(10)


trait DynamicImpls extends Dynamic {
def selectDynamic(method: String): Any = ???
def applyDynamic(method: String)(args: Any*): Any = ???
def applyDynamicNamed(method: String)(args: (String, Any)*): Any = ???
def updateDynamic(method: String)(args: Any*): Any = ???

Paul Phillips

unread,
May 3, 2012, 9:21:41 PM5/3/12
to scala-l...@googlegroups.com
I haven't been keeping up with everything in the dynamic world of
language.dynamics. Has anyone been doing anything interesting? Here's
a little setup rig in case it's useful to anyone.

scala> val x = new Accumulator
x: Accumulator =

scala> x.bippy("hi", "mom").bingo.bong.bong.bong.and(dog = "groucho",
cat = "harpo")
res0: Accumulator = bippy(hi, mom).bingo.bong.bong.bong.and(dog =
groucho, cat = harpo)


trait DynamicThis[+T] extends Dynamic {
this: T =>

def dynamicMissingMethod(which: String, method: String)(args: Any*): Any
private def wrap(which: String, method: String)(args: Any*): this.type = {
dynamicMissingMethod(which, method)(args: _*)
this
}

def selectDynamic(method: String): T =
wrap("selectDynamic", method)()
def applyDynamic(method: String)(args: Any*): T =
wrap("applyDynamic", method)(args: _*)
def applyDynamicNamed(method: String)(args: (String, Any)*): T =
wrap("applyDynamicNamed", method)(args: _*)
def updateDynamic(method: String)(args: Any*): T =
wrap("updateDynamic", method)(args: _*)
}

class Accumulator extends DynamicThis[Accumulator] {
private var calls: List[String] = Nil

def dynamicMissingMethod(which: String, method: String)(args: Any*)
= calls ::= (which match {
case "selectDynamic" => method
case "applyDynamic" => args.mkString(method + "(", ", ", ")")
case "applyDynamicNamed" => args.map({ case (k, v) => k + " = " +
v }).mkString(method + "(", ", ", ")")
case "updateDynamic" => "update (?) "+ args.mkString(method +
"(", ", ", ")")
})

override def toString = calls.reverse mkString "."
}

Stefan Zeiger

unread,
May 4, 2012, 5:28:34 AM5/4/12
to scala-l...@googlegroups.com
On 2012-05-04 1:57, Paul Phillips wrote:
> And if it's intentional, how about we also offer something like this.
> If for no other reason, so people don't have to read the signatures
> out of documentation. Documentation can be wrong... like it is right
> now.
>
> // current documentation
> * foo.arr(10) ~~> foo.applyDynamics("arr")(10)
>
>
> trait DynamicImpls extends Dynamic {
> def selectDynamic(method: String): Any = ???
> def applyDynamic(method: String)(args: Any*): Any = ???
> def applyDynamicNamed(method: String)(args: (String, Any)*): Any = ???
> def updateDynamic(method: String)(args: Any*): Any = ???
> }

Those signatures are not actually required. Dynamic does purely
syntactic rewriting of the method calls, so any signature will do as
long as the arguments match.

Unfortunately, that seems to turn this...

> % m3scala
> Welcome to Scala version 2.10.0-M3 (Java HotSpot(TM) 64-Bit Server VM,
> Java 1.6.0_31).
> Type in expressions to have them evaluated.
> Type :help for more information.
>
> scala> import language.dynamics
> import language.dynamics
>
> scala> def f(x: Dynamic) = x.bippy
> <console>:8: error: value selectDynamic is not a member of Dynamic
> def f(x: Dynamic) = x.bippy

...into a non-trivial problem.

-sz

Paul Phillips

unread,
May 4, 2012, 5:35:44 AM5/4/12
to scala-l...@googlegroups.com
On Fri, May 4, 2012 at 2:28 AM, Stefan Zeiger <sze...@novocode.com> wrote:
> Those signatures are not actually required. Dynamic does purely syntactic
> rewriting of the method calls, so any signature will do as long as the
> arguments match.

Yeah, in my faux checkin branch, it says:

/** An extension of Dynamic which abstractly defines the methods
* eligible to receive dynamic invocations. These are general
* signatures, using `Any` in all positions; more specific
* signatures can be written, but because method parameter types cannot
* be refined in subclasses, you will want to extend Dynamic directly
* to do that.
*/
trait DynamicInterface extends Dynamic {
def selectDynamic(method: String): Any
def applyDynamic(method: String)(args: Any*): Any
def applyDynamicNamed(method: String)(args: (String, Any)*): Any
def updateDynamic(method: String)(args: Any*): Any
}

I also have this guy doing his thing, although given recent events it
seems comically primitive to do reflection this way.

scala> val r = new Dynamic.Reflecto(List(1,2,3))
r: Dynamic.Reflecto = scala.Dynamic$Reflecto@7110506e

scala> r sorted implicitly[Ordering[Int]]
res0: Any = List(1, 2, 3)

scala> r sorted implicitly[Ordering[Int]].reverse
res1: Any = List(3, 2, 1)

Stefan Zeiger

unread,
May 4, 2012, 5:41:48 AM5/4/12
to scala-l...@googlegroups.com
On second thought, I'll take "non-trivial" back and replace it with
"impossible".

val x = new Dynamic { def applyDynamic(method: String)(args: Any*): Any
= ??? }

def foo(x: Dynamic, y: Any) = foo.bippy(y)

becomes

def foo(x: Dynamic, y: Any) = {
// weave some Java reflection magic to find a method m that looks
like an applyDynamic
// check conformance of types in a sloppy way
m.invoke(x, "bippy", y)
}

Looks hackish and non-trivial but doable. On the other hand:

val x = new Dynamic { def applyDynamic[T: Numeric](method: String)(num:
T): T = ??? }

def foo(x: Dynamic, y: Any) = foo.bippy(y)

No way, Jose!

martin odersky

unread,
May 4, 2012, 6:47:12 AM5/4/12
to scala-l...@googlegroups.com
That's right. You are not expected to be able to do anything with Dynamic as such, you need to interact with a specific implementation
trait such as JSObject, or DynamicProxy.

Cheers

 - Martin

martin odersky

unread,
May 4, 2012, 6:49:03 AM5/4/12
to scala-l...@googlegroups.com, Christopher Vogt
I think DynamicInterface would be a good addition. Also see with Christopher Vogt, who has worked an on an implementation of DynamicProxy using reflection. We should make sure that it conforms to the interface we push out.

 - Martin
--
Martin Odersky
Prof., EPFL and Chairman, Typesafe
PSED, 1015 Lausanne, Switzerland
Tel. EPFL: +41 21 693 6863
Tel. Typesafe: +41 21 691 4967

Chris Hodapp

unread,
May 5, 2012, 11:59:42 PM5/5/12
to scala-l...@googlegroups.com
I'm not sure if you'll find it interesting or repugnant, but my SOC 2012 project is dependent on the dynamic world of language.dynamics. https://gist.github.com/2318356. I have not really started yet, though, since I have been finishing up my semester at University. I graduated from my undergraduate program today, so I and have to move tomorrow. I plan to start in earnest next week. 

Eugene Burmako

unread,
May 6, 2012, 3:17:14 AM5/6/12
to scala-l...@googlegroups.com
Wow, sounds great! Would be very interesting to see how far you can advance with this. 

nafg

unread,
May 6, 2012, 9:51:37 PM5/6/12
to scala-l...@googlegroups.com

On Thursday, May 3, 2012 9:21:41 PM UTC-4, Paul Phillips wrote:
I haven't been keeping up with everything in the dynamic world of
language.dynamics.  Has anyone been doing anything interesting? Here's
a little setup rig in case it's useful to anyone.

scala> val x = new Accumulator
x: Accumulator =

scala> x.bippy("hi", "mom").bingo.bong.bong.bong.and(dog = "groucho",
cat = "harpo")
res0: Accumulator = bippy(hi, mom).bingo.bong.bong.bong.and(dog =
groucho, cat = harpo)


Nice! Almost like what I do not with Dynamic but with java.lang.reflect.Proxy, in reactive-web's Javascript DSL. Except of course you have to write an abstract definition (JsStub)...

Reply all
Reply to author
Forward
0 new messages