Objective-D, reflective programming, dynamic typing
Steve Teale
steve.teale at britseyeview.com
Thu Apr 2 11:32:48 PDT 2009
Eljay Wrote:
> /*
>
> Although D 2.0 is a multi-paradigm programming language, it does not support
> two paradigms:
> + reflective programming
> + dynamic typing
>
> Since D 2.0 does not have support for reflective programming, nor support for
> dynamic typing, I thought "What facilities does D 2.0 have which could be used
> to mimic reflective programming and dynamic typing?"
>
> (Unless I'm mistaken, and D 2.0 does support these paradigms. Andrei and Walter
> have been very busy! In which case... oops.)
>
> This toy program is the result.
>
> This toy program does not try to achieve efficient performance.
>
> Id - root class for all dynamic types.
> Msg - a string:string associative array.
> TODO. Need to change to string:Id dictionary, but that's for later.
> TODO. Need to have Id wrapper for string, and other primitives.
> Sel - the selector, which is the "@" key bound to the selector string in the
> string dictionary.
>
> What is lacking?
> - Should be able to add message responders to an object.
> What does this mean?
> Create an object.
> Insert a message responder.
> Send that message, and notice that the object now performs that message.
> Only affect that instantiated object, not the whole class.
>
> - Should be able to add message responders to a class.
> What does this mean?
> If someone has a black box class called MyString, you should be able to inject
> a brand new message responder into that class which affects ALL instances of
> MyString.
> Upshot: you can inject new message handlers to an existing class, which is not
> a class to which you have the source.
>
> - Should be able to override message responders to a class, and inject your own
> message responder.
> What does this mean?
> Let's say you want to do some "first grade debugging" on a class, you should
> be able to programmatically get the message responder of a class (even a class
> to which you do not have the source),
> save that message responder, inject your own diagnostic message responder into
> a class (or into a single instantiated object), output the diagnostics than
> invoke the original message responder.
>
> - Classes themsleves should be singleton (or monostate) objects, which are
> object instantiation factories.
> Objective-C designates class message responders and object message responders
> by (note the leading '+' and '-'):
> + (void)IAmAClassMessageResponder(void)
> - (void)IAmAnObjectMessageReponder(void)
>
> Just as a programmer can do object-oriented programming in pure C, even though
> the C programming language provides no language support for object-oriented
> programming, so too can you do reflective programming in D. Even though D does
> not provide any dynamic typing and reflecting programming support in the D core
> language.
>
> The only thing that is required to do reflective programming and have dynamic
> typing in D is superhuman discipline, and adhering meticulously to a rigid
> programming convention and never ever make a mistake.
>
> */
>
> import std.stdio;
> import std.conv;
>
> alias string[string] Msg;
>
> /*
> ** This is the ultimate root of all reflective objects.
> ** Wouldn't it be nice if this were class object?
> */
> class Id
> {
> void perform(in Msg msg)
> {
> switch(msg["@"])
> {
> default:
> {
> writeln("Unable to perform \"", msg["@"], "\"");
> }
> break;
> }
> }
> };
>
> /*
> ** This is an example of a useful object which does something interesting.
> */
> class IdFoo : Id
> {
> void perform(in Msg msg)
> {
> switch(msg["@"])
> {
> case "add":
> {
> performAdd(msg);
> }
> break;
>
> case "sub":
> {
> performSub(msg);
> }
> break;
>
> case "mul":
> {
> performMul(msg);
> }
> break;
>
> case "div":
> {
> performDiv(msg);
> }
> break;
>
> default:
> {
> super.perform(msg);
> }
> break;
> }
> }
>
> void performAdd(in Msg msg)
> {
> double a = toDouble(msg["a"]);
> double b = toDouble(msg["b"]);
> writeln(a, " + ", b, " = ", (a + b));
> }
>
> void performSub(in Msg msg)
> {
> double a = toDouble(msg["a"]);
> double b = toDouble(msg["b"]);
> writeln(a, " - ", b, " = ", (a - b));
> }
>
> void performMul(in Msg msg)
> {
> double a = toDouble(msg["a"]);
> double b = toDouble(msg["b"]);
> writeln(a, " * ", b, " = ", (a * b));
> }
>
> void performDiv(in Msg msg)
> {
> double a = toDouble(msg["a"]);
> double b = toDouble(msg["b"]);
> writeln(a, " / ", b, " = ", (a / b));
> }
> }
>
> /*
> ** This is an example of a null object.
> ** Imagine that the null object is a noisy debugging object, used to substitute
> ** in for an object which has been destroyed.
> */
> class IdNull : Id
> {
> void perform(in Msg msg)
> {
> switch(msg["@"])
> {
> default:
> {
> performDiscard(msg);
> }
> break;
> }
> }
>
> void performDiscard(in Msg msg)
> {
> writeln("Discard ", msg["@"]);
> }
> }
>
> /*
> ** This is an example of a proxy object, which forwards message to an object
> ** elsewhere.
> **
> ** Imagine that the other object exists on another computer, and this forwarding
> ** object sends messages to the remote object over an IP/TCP connection.
> */
> class IdForward : Id
> {
> void perform(in Msg msg)
> {
> switch(msg["@"])
> {
> default:
> {
> performForward(msg);
> }
> break;
> }
> }
>
> void performForward(in Msg msg)
> {
> writeln("Proxy object forwarding message ", msg["@"]);
> forwardObj.perform(msg);
> }
>
> this(Id obj)
> {
> forwardObj = obj;
> }
>
> Id forwardObj;
> }
>
> void Exercise(Id obj)
> {
> Msg msg;
>
> // [obj addWithA:5 withB:3] -- Objective-C
> // obj(add a:5 b:3) -- Pseudo-D ... perhaps?
> // obj(add a:"5" b:"3") closer to what we are actually doing
> // but not what's ultimately desired.
> msg["@"] = "add"; // Just using "add", but could have been "addWithA:withB:"
> msg["a"] = "5";
> msg["b"] = "3";
> obj.perform(msg);
>
> // [obj subWithA:5 withB:3]
> // obj(sub a:5 b:3)
> msg["@"] = "sub";
> obj.perform(msg);
>
> // [obj mulWithA:5 withB:3]
> // obj(mul a:5 b:3)
> msg["@"] = "mul";
> obj.perform(msg);
>
> // [obj divWithA:5 withB:3]
> // obj(div a:5 b:3)
> msg["@"] = "div";
> obj.perform(msg);
>
> // [obj fooWithA:5 withB:3]
> // obj(foo a:5 b:3)
> msg["@"] = "foo";
> obj.perform(msg);
> }
>
> void main()
> {
> Id obj = new IdFoo;
> writeln(">>> Exercise IdFoo");
> Exercise(obj);
>
> obj = new IdNull;
> writeln("\n>>> Exercise IdNull");
> Exercise(obj);
>
> obj = new IdForward(new IdFoo);
> writeln("\n>>> Exercise IdForward(IdFoo)");
> Exercise(obj);
>
> writeln("---done---");
> }
>
>
Could you please give a three or four line example of what it is you want to achieve.
More information about the Digitalmars-d
mailing list