www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Dynamic method example in TDPL

reply Joel Christensen <joelcnz gmail.com> writes:
I've typed this example program in, but it doesn't compile. I looked up 
the The D programming language errata but it wasn't listed. I'm using 
DMD v2.048.


/** Date: Aug 20, 2010 This was copied from TDPL book pages 386 - 387 */ module dynamicmethods; import std.stdio; import std.variant; alias Variant delegate(Dynamic self, Variant[] args...) DynMethod; class Dynamic { private DynMethod[string] methods; void addMethod(string name, DynMethod m) { methods[name] = m; } void removeMethod(string name) { methods.remove(name); } // Dispatch dynamically on method Variant call(string methodName, Variant[] args...) { return methods[methodName](this, args); } // Provide syntactic sugar with opDispatch Variant opDispatch(string m, Args)(Args args...) { Variant[] packedArgs = new Variant[args.length]; foreach (i, arg; args) { packedArgs[i] = Variant(arg); } return call(m, args); } } void main() { auto obj = new Dynamic; obj.addMethod("sayHello", Variant(Dynamic, Variant[]) { //#error here. (found '{' expecting ',' writeln("Hello, world!"); return Variant(); }); obj.sayHello(); // Prints "Hello, world!" } <<
Aug 20 2010
next sibling parent reply Stanislav Blinov <blinov loniir.ru> writes:
  20.08.2010 13:00, Joel Christensen wrote:

There seem to be quite a few errors in this one:

 /**
     Date: Aug 20, 2010
     This was copied from TDPL book pages 386 - 387
 */
 module dynamicmethods;

 import std.stdio;
 import std.variant;

 alias Variant delegate(Dynamic self, Variant[] args...) DynMethod;

 class Dynamic {
     private DynMethod[string] methods;
     void addMethod(string name, DynMethod m) {
         methods[name] = m;
     }
     void removeMethod(string name) {
         methods.remove(name);
     }
     // Dispatch dynamically on method
     Variant call(string methodName, Variant[] args...) {
         return methods[methodName](this, args);
     }
     // Provide syntactic sugar with opDispatch
     Variant opDispatch(string m, /*was: Args*/Args...)(/*was: Args 
 args...*/Args args) { // There should've been variadic template 
 instead of variadic function
         Variant[] packedArgs = new Variant[args.length];
         foreach (i, arg; args) {
             packedArgs[i] = Variant(arg);
         }
         return call(m, /*was: args*/packedArgs); // args was used 
 instead of packedArgs
     }
 }

 void main() {
     auto obj = new Dynamic;
     obj.addMethod("sayHello",
         delegate Variant(Dynamic, Variant[]...) { // delegate keyword 
 was missing, and it wasn't matching DynMethod signature
             writeln("Hello, world!");
             return Variant();
         });
     obj.sayHello(); // Prints "Hello, world!"
 }
Maybe Andrej can add this one to errata too? :)
Aug 20 2010
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
You mean Andrei?

P.S. anyone can edit the errata page. It has a history backup, so if someone
accidentally screws up something you can roll back to a previous version. If
you find something that needs to be added, go ahead and do it.

Btw., I haven't reached that page yet. :p

Stanislav Blinov Wrote:

   20.08.2010 13:00, Joel Christensen wrote:
 
 There seem to be quite a few errors in this one:
 
 /**
     Date: Aug 20, 2010
     This was copied from TDPL book pages 386 - 387
 */
 module dynamicmethods;

 import std.stdio;
 import std.variant;

 alias Variant delegate(Dynamic self, Variant[] args...) DynMethod;

 class Dynamic {
     private DynMethod[string] methods;
     void addMethod(string name, DynMethod m) {
         methods[name] = m;
     }
     void removeMethod(string name) {
         methods.remove(name);
     }
     // Dispatch dynamically on method
     Variant call(string methodName, Variant[] args...) {
         return methods[methodName](this, args);
     }
     // Provide syntactic sugar with opDispatch
     Variant opDispatch(string m, /*was: Args*/Args...)(/*was: Args 
 args...*/Args args) { // There should've been variadic template 
 instead of variadic function
         Variant[] packedArgs = new Variant[args.length];
         foreach (i, arg; args) {
             packedArgs[i] = Variant(arg);
         }
         return call(m, /*was: args*/packedArgs); // args was used 
 instead of packedArgs
     }
 }

 void main() {
     auto obj = new Dynamic;
     obj.addMethod("sayHello",
         delegate Variant(Dynamic, Variant[]...) { // delegate keyword 
 was missing, and it wasn't matching DynMethod signature
             writeln("Hello, world!");
             return Variant();
         });
     obj.sayHello(); // Prints "Hello, world!"
 }
Maybe Andrej can add this one to errata too? :)
Aug 20 2010
next sibling parent Stanislav Blinov <blinov loniir.ru> writes:
  20.08.2010 15:49, Andrej Mitrovic wrote:
 You mean Andrei?
Nope :p
 P.S. anyone can edit the errata page. It has a history backup, so if someone
accidentally screws up something you can roll back to a previous version. If
you find something that needs to be added, go ahead and do it.
Yeah, I know that. It's just that I can't do it till tomorrow, because I don't have Internet at work except for mail :|
 Btw., I haven't reached that page yet. :p
Aug 20 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
Sorry to resurrect an old (4 days) thread.
I modified the example a bit, getting rid of '...' in DynMethod and
modifying opDispatch as Stanislav suggested. It works, and it's fun to play
with:

module dynamicmethods;

import std.stdio;
import std.conv;
import std.variant;

alias Variant delegate(Dynamic self, Variant[] args) DynMethod;

class Dynamic {
       private DynMethod[string] methods;
       void addMethod(string name, DynMethod m) {
               methods[name] = m;
       }
       void removeMethod(string name) {
               methods.remove(name);
       }
       // Dispatch dynamically on method
       Variant call(string methodName, Variant[] args) {
               return methods[methodName](this, args);
       }
       // Provide syntactic sugar with opDispatch
       Variant opDispatch(string m, Args...)(Args args) {
               Variant[] packedArgs = new Variant[args.length];
               foreach (i, arg; args) {
                       packedArgs[i] = Variant(arg);
               }
               return call(m, packedArgs);
       }
}

void main() {
       auto obj = new Dynamic;
       obj.addMethod("sayHello",
               (Dynamic, Variant[]) {
                       writeln("Hello, world!");
                       return Variant();
               });
       // m is just the previous anonymous delegate.
       DynMethod m = (Dynamic, Variant[]) {
                       writeln("Hello, world!");
                       return Variant();
                     };
       obj.sayHello(); // Prints "Hello, world!"
       // Now, what about a meta-method? test adds a bunch of methods in one
go:
       obj.addMethod("test",
                     (Dynamic self, Variant[] args) {
                        writeln("the dynamic class currently has ",
self.methods.length, " methods: ", self.methods.keys);
                        foreach(i,arg; args)
self.addMethod("method"~to!string(i), arg.get!DynMethod);
                        writeln("Now, the dynamic class has ",
self.methods.length, " methods: ", self.methods.keys);
                        return Variant();
                     });
        obj.test(m); // adds m to obj, as method0
        obj.method0(); // tests it. It prints "Hello, world!"
}
Aug 24 2010
prev sibling parent reply Joel Christensen <joelcnz gmail.com> writes:
Thanks for the fix up Philippe.

Just a little note. Where it says 'DynMethod m', you can put 'auto m', 
but I'm wondering is it some times clearer to have the class name even 
though 'auto' works.
Aug 31 2010
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Wed, Sep 1, 2010 at 01:24, Joel Christensen <joelcnz gmail.com> wrote:

 Thanks for the fix up Philippe.

 Just a little note. Where it says 'DynMethod m', you can put 'auto m', but
 I'm wondering is it some times clearer to have the class name even though
 'auto' works.
It depends on what you prefer. auto adds flexibility: if you use auto a lot, you can change the 'typed' parts of your code and the parts with auto will likely stay the same, propagating the change without hiccup, which is well and good. But you also loose sight of what the 'current' type is. The compiler knows it perfectly well, though, and you can count on static typing to help you when it can. Personally, I'm a bit leery of using auto in complex, recursive, templated code: not so long ago, auto regularly created nasty forward declaration errors. I think some were squashed recently, but I'm still testing the water here.
Sep 01 2010