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