Private and Package dynamic dispatch, implemented as a library template!

Andrej Mitrovic andrej.mitrovich at gmail.com
Sat Mar 30 03:27:31 PDT 2013


A few months ago I posted this:
http://forum.dlang.org/thread/mailman.1030.1360125437.22503.digitalmars-d@puremagic.com

And this wiki page:
http://wiki.dlang.org/Dispatching_an_object_based_on_its_dynamic_type

But now I've implemented a similar feature for class methods.

Let's say you have a class hierarchy in your library and you want to
use virtual methods to implement specific functionality for each
class. However you have one requirement: the user should not have
access to these methods because they're supposed to be internal to the
library. For one example, they might be needed to initialize some
state based on the dynamic type before actually calling some public
virtual method.

Herein lies the problem, because you cannot have virtual private or
package methods. But thanks to D's metaprogramming abilities you can
dispatch to the appropriate private or package methods based on the
dynamic type of the object, and this can all be abstracted away with a
single D template.

All the user has to do is:

1) Instantiate the magical template in module-scope (you'll see why
this is important in a second), and pass leaf class types so the
entire class hierarchy is registered with the template.
2) When invoking class methods, prepend "dynamic" to the call. The
name of this magic namespace can be chosen by the user based on the
template instance in step 1.
3) There is no step 3!

Here's what typical user-code looks like at the call site:

class A     { private void foo(int x) { writefln("A.foo: %s", x); } }
class B : A { private void foo(int x) { writefln("B.foo: %s", x); } }
class C : B { private void foo(int x) { writefln("C.foo: %s", x); } }
class D : B { private void foo(int x) { writefln("D.foo: %s", x); } }
class E : B { }

// pass leaf class types so they can be registered
alias DynamicDispatch!(C, D, E) dynamic;

void main()
{
    A a = new A;
    A b = new B;
    A c = new C;
    A d = new D;
    A e = new E;

    a.dynamic.foo(1);
    b.dynamic.foo(1);
    c.dynamic.foo(1);
    d.dynamic.foo(1);
    e.dynamic.foo(1);
}

Thanks to UFCS the API itself is extremely easy to use.

The full implementation: http://dpaste.dzfl.pl/08278225


More information about the Digitalmars-d mailing list