On Tue, Dec 01, 2009 at 03:55:31PM +0300, Denis Koroskin wrote:
> I believe there will soon be a library type that would allow that.

Here's my first try. I don't have the the new compiler handy and am in a
rush, so I'm doing it hacky.

With the svn compiler, you should be able to almost run this like you'd
expect.

Running it prints:
        Running statically defined: test(10)
        Running dynamically defined test(0)
        object.Exception: no such method text

My vararg code apparently is broken, but meh.


========

import std.stdio;
import std.variant;
import std.stdarg;

class A { // this is our dynamic class
        void test(int a) {
                writefln("Running statically defined: test(%d)", a);
        }

        // Just like in javascript...
        A delegate(...)[string] dynamicFunctions;

        // Return value tells if we should forward to static methods
        bool dynamicCall(string name, out A ret, ...) {
                if(auto fun = name in dynamicFunctions) {
                        ret = (*fun)(_arguments);
                        return true;
                }

                return false;
        }

        void dynamicBind(string name, A delegate(...) fun) {
                dynamicFunctions[name] = fun;
        }

        A opDispatch(string a)(...) {
                // If we're assigning a delegate, bind it as a member
                if(_arguments[0] == typeid(A delegate(...))) {
                        dynamicBind(a, *(cast(A delegate(...)*)(_argptr)));
                        return null;
                }

                // If it is in the dynamic list, run that
                A ret;
                if(dynamicCall(a, ret, _arguments))
                        return ret;

                // If not, we'll look it up in our static table

                int arg = va_arg!(int)(_argptr);
                static if(__traits(hasMember, this, a)) {
                        A var;


                        // gah, I wish auto var = fun() worked when fun returns
                        // void.
                        static if(__traits(compiles,
                            var = __traits(getMember, this, a)(arg)))
                                return __traits(getMember, this, a)(arg);
                        else {
                                // Could be improved by trying to construct a
                                // dynamic instance from the return value,
                                // whatever it is
                                __traits(getMember, this, a)(arg);
                                return null;
                        }
                }
                else
                        throw new Exception("no such method " ~ a);
        }
}

void main() {
        A a = new A;

        // no dynamically defined members, so this should call the static
        a.opDispatch!("test")(10);

        // dynamically define a member to override the static one
        a.opDispatch!("test")(delegate A(int num) { 
                writefln("Running dynamically defined test(%d)", num);
                return null;
        });

        // see what runs
        a.opDispatch!("test")(20);

        // should throw method not defined
        a.opDispatch!("text")(30);
}

=========

If you have the svn compiler, you should be able to replace those opDispatchs
with
        a.test = 10;
and stuff like that.



There's one thing though: I think the patch checks static stuff first, then
if none of that matches, it forwards to opDispatch.

For this to work like in Javascript, it will need a small change.


1) If opDispatch is defined, forward the method do it
2) If this compiles, do nothing more -- assume the opDispatch handled it
3) If not, do a normal static member lookup

If opDispatch is not defined for the class, do nothing special - treat it
like you normally do in D.


The downside is you must either put a static constraint on what your opDispatch
does (easy - static assert(0); if you don't handle it) or forward to your
static members yourself, but the upside is it lets dynamic method overriding
like I do here.

I think it would be a net positive. Assuming this doesn't work already, of
course.

-- 
Adam D. Ruppe
http://arsdnet.net

Reply via email to