www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - D RTTI?

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
I know D doesn't really have RTTI yet, but I'm experimenting with
"faking" it by doing something like:

	class A {
		string prop1;
		int prop2;
		...
		void serialize() {
			__serialize(this);
		}
	}

	void __serialize(T)(T obj) {
		writeln(typeid(obj));
		foreach (name; __traits(derivedMembers, T)) {
			writefln("%s = %s", name,
				__traits(getMember,obj,name));
		}
	}

The only thing is, serialize() has to be declared in every derived
class, because T needs to be known at compile-time. Is there a way to
"automate" this? I.e., automatically insert the serialize() boilerplate
code into derived classes?

(P.S.  D just took on brand new levels of cool when I realized I could
do something like this. Imagine doing this with C++ templates...  ugh!
What a painful thought!)


T

-- 
Tech-savvy: euphemism for nerdy.
Mar 05 2012
next sibling parent reply Justin Whear <justin economicmodeling.com> writes:
On Mon, 05 Mar 2012 12:16:14 -0800, H. S. Teoh wrote:

 I know D doesn't really have RTTI yet, but I'm experimenting with
 "faking" it by doing something like:
 
 	class A {
 		string prop1;
 		int prop2;
 		...
 		void serialize() {
 			__serialize(this);
 		}
 	}
 
 	void __serialize(T)(T obj) {
 		writeln(typeid(obj));
 		foreach (name; __traits(derivedMembers, T)) {
 			writefln("%s = %s", name,
 				__traits(getMember,obj,name));
 		}
 	}
 
 The only thing is, serialize() has to be declared in every derived
 class, because T needs to be known at compile-time. Is there a way to
 "automate" this? I.e., automatically insert the serialize() boilerplate
 code into derived classes?
 
 (P.S.  D just took on brand new levels of cool when I realized I could
 do something like this. Imagine doing this with C++ templates...  ugh!
 What a painful thought!)
 
 
 T

The normal approach is to use a string mixin statement in each derived class: template Serializable() { enum Serializable = q{...your code here...}; } class B : A { mixin(Serializable); } Unfortunately, I don't believe there's any mechanism to order derived classes to automatically perform the mixin.
Mar 05 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Mar 05, 2012 at 08:41:53PM +0000, Justin Whear wrote:
 On Mon, 05 Mar 2012 12:16:14 -0800, H. S. Teoh wrote:
 
 I know D doesn't really have RTTI yet, but I'm experimenting with
 "faking" it by doing something like:
 
 	class A {
 		string prop1;
 		int prop2;
 		...
 		void serialize() {
 			__serialize(this);
 		}
 	}
 
 	void __serialize(T)(T obj) {
 		writeln(typeid(obj));
 		foreach (name; __traits(derivedMembers, T)) {
 			writefln("%s = %s", name,
 				__traits(getMember,obj,name));
 		}
 	}
 
 The only thing is, serialize() has to be declared in every derived
 class, because T needs to be known at compile-time. Is there a way to
 "automate" this? I.e., automatically insert the serialize() boilerplate
 code into derived classes?
 
 (P.S.  D just took on brand new levels of cool when I realized I could
 do something like this. Imagine doing this with C++ templates...  ugh!
 What a painful thought!)
 
 
 T

The normal approach is to use a string mixin statement in each derived class: template Serializable() { enum Serializable = q{...your code here...}; } class B : A { mixin(Serializable); } Unfortunately, I don't believe there's any mechanism to order derived classes to automatically perform the mixin.

OK, it's a bit ugly I supopse, but I can live with that. Is there a way to tell whether or not a given class is a derived class or not? I'm using the Serializable template to insert serialize() into the class, and for derived classes I need to insert "override void serialize() ..." but for the base class I have to omit "override". How can I detect this in the template? Thanks! T -- No! I'm not in denial!
Mar 05 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 03/05/2012 11:33 PM, H. S. Teoh wrote:
 On Mon, Mar 05, 2012 at 08:41:53PM +0000, Justin Whear wrote:
 On Mon, 05 Mar 2012 12:16:14 -0800, H. S. Teoh wrote:

 I know D doesn't really have RTTI yet, but I'm experimenting with
 "faking" it by doing something like:

 	class A {
 		string prop1;
 		int prop2;
 		...
 		void serialize() {
 			__serialize(this);
 		}
 	}

 	void __serialize(T)(T obj) {
 		writeln(typeid(obj));
 		foreach (name; __traits(derivedMembers, T)) {
 			writefln("%s = %s", name,
 				__traits(getMember,obj,name));
 		}
 	}

 The only thing is, serialize() has to be declared in every derived
 class, because T needs to be known at compile-time. Is there a way to
 "automate" this? I.e., automatically insert the serialize() boilerplate
 code into derived classes?

 (P.S.  D just took on brand new levels of cool when I realized I could
 do something like this. Imagine doing this with C++ templates...  ugh!
 What a painful thought!)


 T

The normal approach is to use a string mixin statement in each derived class: template Serializable() { enum Serializable = q{...your code here...}; } class B : A { mixin(Serializable); } Unfortunately, I don't believe there's any mechanism to order derived classes to automatically perform the mixin.

OK, it's a bit ugly I supopse, but I can live with that. Is there a way to tell whether or not a given class is a derived class or not? I'm using the Serializable template to insert serialize() into the class, and for derived classes I need to insert "override void serialize() ..." but for the base class I have to omit "override". How can I detect this in the template? Thanks! T

You can check typeof(this).
Mar 05 2012
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Mar 06, 2012 at 12:03:48AM +0100, Timon Gehr wrote:
 On 03/05/2012 11:33 PM, H. S. Teoh wrote:

[...]
Is there a way to tell whether or not a given class is a derived
class or not? I'm using the Serializable template to insert
serialize() into the class, and for derived classes I need to insert
"override void serialize() ..." but for the base class I have to omit
"override". How can I detect this in the template?


[...]
 
 You can check typeof(this).

Ahh, that's what I was looking for. Awesome!!! By combining typeof(this) with __traits(hasMember,...), I can actually insert missing methods into a class if they haven't been defined yet, or override existing methods if they are already defined in the base class: template Serializable() { enum Serializable = q{ static if (__traits(hasMember, typeof(this), "serializable")) { // Override existing method override void serialize(...); } else { // Insert missing method void serialize(...); } }; } class A { // This causes A to acquire serialize() mixin(Serializable!()); } class B : A { // This causes B to override serialize() mixin(Serializable!()); } D is too cool for words. T -- For every argument for something, there is always an equal and opposite argument against it. Debates don't give answers, only wounded or inflated egos.
Mar 05 2012
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Mar 05, 2012 at 03:26:01PM -0800, H. S. Teoh wrote:
[...]
 	template Serializable() {
 		enum Serializable = q{
 			static if (__traits(hasMember, typeof(this),
 					"serializable"))

[...] Ugh, that last string should read "serialize".
 			{
 				// Override existing method
 				override void serialize(...);
 			}
 			else
 			{
 				// Insert missing method
 				void serialize(...);
 			}
 		};
 	}
 
 	class A {
 		// This causes A to acquire serialize()
 		mixin(Serializable!());
 	}
 
 	class B : A {
 		// This causes B to override serialize()
 		mixin(Serializable!());
 	}
 
 
 D is too cool for words.
 
 
 T
 
 -- 
 For every argument for something, there is always an equal and opposite
argument against it. Debates don't give answers, only wounded or inflated egos.

-- "How are you doing?" "Doing what?"
Mar 05 2012
prev sibling parent "Kenji Hara" <k.hara.pg gmail.com> writes:
On Monday, 5 March 2012 at 22:31:58 UTC, H. S. Teoh wrote:
 OK, it's a bit ugly I supopse, but I can live with that.

 Is there a way to tell whether or not a given class is a 
 derived class
 or not? I'm using the Serializable template to insert 
 serialize() into
 the class, and for derived classes I need to insert "override 
 void
 serialize() ..." but for the base class I have to omit 
 "override". How
 can I detect this in the template?

How about "wrapper template class"? --------- import std.stdio; class Serialized(T) : T { // 2.059 new feature: class template constructor this(A...)(A args) { static if (is(typeof(super(args)))) super(args); } void serialize() { foreach (i, name; __traits(allMembers, T)) { mixin("alias "~name~" Member;"); static if (is(typeof(Member) == function)) {} // member function else static if (!is(typeof(Member))) {} // has no type is member template else static if (is(Member)) {} // nested type declaration else writefln("[%d] %s", i, name); // field!! } } } class A { private int value; } class B : A { private string key; this(string s){ key = s; } } void main() { auto a = new Serialized!A(); a.serialize(); writeln("----"); auto b = new Serialized!B("hello"); b.serialize(); } output: --------- [0] value ---- [0] key [2] value
Mar 05 2012
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2012-03-05 21:16, H. S. Teoh wrote:
 I know D doesn't really have RTTI yet, but I'm experimenting with
 "faking" it by doing something like:

 	class A {
 		string prop1;
 		int prop2;
 		...
 		void serialize() {
 			__serialize(this);
 		}
 	}

 	void __serialize(T)(T obj) {
 		writeln(typeid(obj));
 		foreach (name; __traits(derivedMembers, T)) {
 			writefln("%s = %s", name,
 				__traits(getMember,obj,name));
 		}
 	}

 The only thing is, serialize() has to be declared in every derived
 class, because T needs to be known at compile-time. Is there a way to
 "automate" this? I.e., automatically insert the serialize() boilerplate
 code into derived classes?

 (P.S.  D just took on brand new levels of cool when I realized I could
 do something like this. Imagine doing this with C++ templates...  ugh!
 What a painful thought!)

If you actually want serialization, and this was not just an example, you can use Orange: https://github.com/jacob-carlborg/orange http://www.dsource.org/projects/orange/ -- /Jacob Carlborg
Mar 05 2012
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Mar 06, 2012 at 08:17:07AM +0100, Jacob Carlborg wrote:
 On 2012-03-05 21:16, H. S. Teoh wrote:
I know D doesn't really have RTTI yet, but I'm experimenting with
"faking" it by doing something like:

	class A {
		string prop1;
		int prop2;
		...
		void serialize() {
			__serialize(this);
		}
	}

	void __serialize(T)(T obj) {
		writeln(typeid(obj));
		foreach (name; __traits(derivedMembers, T)) {
			writefln("%s = %s", name,
				__traits(getMember,obj,name));
		}
	}


[...]
 If you actually want serialization, and this was not just an
 example, you can use Orange:
 
 https://github.com/jacob-carlborg/orange
 http://www.dsource.org/projects/orange/

[...] For my purposes, I will eventually need to serialize only a subset of an object's properties, and only for a certain class of objects. Does Orange support selective serializations? T -- Having a smoking section in a restaurant is like having a peeing section in a swimming pool. -- Edward Burr
Mar 06 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-03-06 19:17, H. S. Teoh wrote:
 On Tue, Mar 06, 2012 at 08:17:07AM +0100, Jacob Carlborg wrote:
 On 2012-03-05 21:16, H. S. Teoh wrote:
 I know D doesn't really have RTTI yet, but I'm experimenting with
 "faking" it by doing something like:

 	class A {
 		string prop1;
 		int prop2;
 		...
 		void serialize() {
 			__serialize(this);
 		}
 	}

 	void __serialize(T)(T obj) {
 		writeln(typeid(obj));
 		foreach (name; __traits(derivedMembers, T)) {
 			writefln("%s = %s", name,
 				__traits(getMember,obj,name));
 		}
 	}


[...]
 If you actually want serialization, and this was not just an
 example, you can use Orange:

 https://github.com/jacob-carlborg/orange
 http://www.dsource.org/projects/orange/

[...] For my purposes, I will eventually need to serialize only a subset of an object's properties, and only for a certain class of objects. Does Orange support selective serializations?

Yes, but by default is serializes everything you give it. Orange supports several ways of customizing the serialization. You can choose to not serialize specific fields or a whole class: class Foo { int a; int b; mixin NonSerialized!(b); // will not serialize "b" } class Foo { int a; int b; mixin NonSerialized; // will not serialize "Foo" at all } If you want to customize the serialization process in even more detail that's possible as well, by implementing the Serializable interface: class Foo : Serializable { int a; void toData (Serializer serializer, Serializer.Data key) { serializer.serialize(a, "b"); } void fromData (Serializer serializer, Serializer.Data key) { a = serializer.deserialize!(int)("b"); } } Actually, you don't need to implement the interface, it will use compile time introspection to check if the methods are available. Or the unintrusive approach: class Foo { int a; } auto dg = (Foo value, Serializer serializer, Serializer.Data key) { serializer.serialize(a, "b"); } Serializer.registerSerializer!(Foo)(dg); You can find the docs here: http://dl.dropbox.com/u/18386187/orange_docs/orange.serialization.Serializer.html In the docs, don't forget the "package" tab. -- /Jacob Carlborg
Mar 06 2012