www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - InstanceOf

reply "Lemonfiend" <lemon fie.nd> writes:
I'm trying to create a fairly generic component system, where an 
object iterates over a bunch of other objects that all implement 
a certain interface.
And this all works fine, however, I would also like to be able to 
get objects of a specific type (a la instanceOf), and I can't 
figure out how to do it.

Could anyone help me out?

[code]
interface I
{
	void update();
	void write();
}

class A : I
{
	int n;
	
	void update()
	{
		n++;
	}

	void write()
	{
		writeln(n);
	}
}

class B : I
{
	int m;
	
	void update()
	{
		m--;
	}

	void write()
	{
		writeln(m);
	}
}

class C
{
	I[] array;

	void addElem(I elem)
	{
		array ~= elem;
	}

	void loop()
	{
		foreach(elem; array)
			elem.update();
	}

	void writeAll()
	{
		foreach(elem; array)
			elem.write();
	}

	void writeB()
	{
		// Only call .write on B's
		// How do I get the B's from the array of I's?
	}
}

void main()
{
	C c = new C();

	c.addElem(new A());
	c.addElem(new B());

	c.loop();

	c.writeAll();

	c.writeB(); // This is the problem
}
[/code]
Jun 23 2013
next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 06/23/13 13:04, Lemonfiend wrote:
     void writeAll()
     {
         foreach(elem; array)
             elem.write();
     }
 
     void writeB()
     {
         // Only call .write on B's
         // How do I get the B's from the array of I's?
     }
void writeB() { foreach(elem; array) if (auto b = cast(B)elem) b.write(); } artur
Jun 23 2013
prev sibling next sibling parent "Chris Cain" <clcain uncg.edu> writes:
On Sunday, 23 June 2013 at 11:04:59 UTC, Lemonfiend wrote:
 ...
 	void writeAll()
 	{
 		foreach(elem; array)
 			elem.write();
 	}

 	void writeB()
 	{
 		// Only call .write on B's
 		// How do I get the B's from the array of I's?
 	}
http://dlang.org/expression.html#CastExpression So, this should do it: void writeB() { foreach(elem; array) if(cast(B) elem) elem.write(); } You can also do some things like this, if you want to use something specific to Bs: if(auto b = cast(B) elem) b.bSpecificMethod();
Jun 23 2013
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Sunday, 23 June 2013 at 11:04:59 UTC, Lemonfiend wrote:
 I'm trying to create a fairly generic component system, where 
 an object iterates over a bunch of other objects that all 
 implement a certain interface.
 And this all works fine, however, I would also like to be able 
 to get objects of a specific type (a la instanceOf), and I 
 can't figure out how to do it.

 Could anyone help me out?

 [code]
 interface I
 {
 	void update();
 	void write();
 }

 class A : I
 {
 	int n;
 	
 	void update()
 	{
 		n++;
 	}

 	void write()
 	{
 		writeln(n);
 	}
 }

 class B : I
 {
 	int m;
 	
 	void update()
 	{
 		m--;
 	}

 	void write()
 	{
 		writeln(m);
 	}
 }

 class C
 {
 	I[] array;

 	void addElem(I elem)
 	{
 		array ~= elem;
 	}

 	void loop()
 	{
 		foreach(elem; array)
 			elem.update();
 	}

 	void writeAll()
 	{
 		foreach(elem; array)
 			elem.write();
 	}

 	void writeB()
 	{
 		// Only call .write on B's
 		// How do I get the B's from the array of I's?
 	}
 }

 void main()
 {
 	C c = new C();

 	c.addElem(new A());
 	c.addElem(new B());

 	c.loop();

 	c.writeAll();

 	c.writeB(); // This is the problem
 }
 [/code]
foreach (I i; array) { if (B b = cast(B) i) { ... } }
Jun 23 2013
parent reply "Lemonfiend" <lemon fie.nd> writes:
 foreach (I i; array) {
     if (B b = cast(B) i) { ... }
 }
Thanks all 3 of you for the quick and identical answers. :) It had not occurred to me to use a cast for this, but indeed the language ref says the same: "In order to determine if an object o is an instance of a class B use a cast" It does a bit inelegant to me.. Or are casts simply extremely cheap?
Jun 23 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 06/23/2013 01:26 PM, Lemonfiend wrote:
 foreach (I i; array) {
     if (B b = cast(B) i) { ... }
 }
Thanks all 3 of you for the quick and identical answers. :) It had not occurred to me to use a cast for this, but indeed the language ref says the same: "In order to determine if an object o is an instance of a class B use a cast" It does a bit inelegant to me.. Or are casts simply extremely cheap?
Casts are as cheap as testing whether an object is an instance of a certain class. Having the cast evaluate to a nullable reference is certainly more elegant than having instanceof and cast as separate constructs, where the cast may throw.
Jun 23 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-06-23 13:26, Lemonfiend wrote:
 foreach (I i; array) {
     if (B b = cast(B) i) { ... }
 }
Thanks all 3 of you for the quick and identical answers. :) It had not occurred to me to use a cast for this, but indeed the language ref says the same: "In order to determine if an object o is an instance of a class B use a cast" It does a bit inelegant to me.. Or are casts simply extremely cheap?
You can do something like this as well: if (i.classinfo is B.classinfo) { } But doing the cast is more efficient if you want to use the object of as the type you're checking for. You can also hide the cast in a function if you want to be a bit more clear of the intent: T instanceOf (T) (Object value) { return cast(T) value); } if (i.instanceOf!(B)) { } -- /Jacob Carlborg
Jun 23 2013
parent reply "Lemonfiend" <lemon fie.nd> writes:
On Sunday, 23 June 2013 at 15:15:16 UTC, Jacob Carlborg wrote:
 On 2013-06-23 13:26, Lemonfiend wrote:
 foreach (I i; array) {
    if (B b = cast(B) i) { ... }
 }
Thanks all 3 of you for the quick and identical answers. :) It had not occurred to me to use a cast for this, but indeed the language ref says the same: "In order to determine if an object o is an instance of a class B use a cast" It does a bit inelegant to me.. Or are casts simply extremely cheap?
You can do something like this as well: if (i.classinfo is B.classinfo) { } But doing the cast is more efficient if you want to use the object of as the type you're checking for.
Using the .classinfo is what I looked at before asking here. However, according to the specs: ".classinfo applied to an interface gives the information for the interface, not the class it might be an instance of." So the i.classinfo and B.classinfo would be different?
 You can also hide the cast in a function if you want to be a 
 bit more clear of the intent:

 T instanceOf (T) (Object value)
 {
     return cast(T) value);
 }

 if (i.instanceOf!(B)) { }
This is indeed what I did :)
Jun 23 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-06-23 17:29, Lemonfiend wrote:

 Using the .classinfo is what I looked at before asking here.
 However, according to the specs:
 ".classinfo applied to an interface gives the information for the
 interface, not the class it might be an instance of."
 So the i.classinfo and B.classinfo would be different?
That might be the case, didn't think of that. In that case you need casts anyway. -- /Jacob Carlborg
Jun 23 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 23 Jun 2013 11:29:10 -0400, Lemonfiend <lemon fie.nd> wrote:

 On Sunday, 23 June 2013 at 15:15:16 UTC, Jacob Carlborg wrote:
 On 2013-06-23 13:26, Lemonfiend wrote:
 foreach (I i; array) {
    if (B b = cast(B) i) { ... }
 }
Thanks all 3 of you for the quick and identical answers. :) It had not occurred to me to use a cast for this, but indeed the language ref says the same: "In order to determine if an object o is an instance of a class B use a cast" It does a bit inelegant to me.. Or are casts simply extremely cheap?
You can do something like this as well: if (i.classinfo is B.classinfo) { } But doing the cast is more efficient if you want to use the object of as the type you're checking for.
Using the .classinfo is what I looked at before asking here. However, according to the specs: ".classinfo applied to an interface gives the information for the interface, not the class it might be an instance of." So the i.classinfo and B.classinfo would be different?
1. Use typeid(i), not i.classinfo, classinfo is old-style. 2. Yes, typeid(i) will give you interface class info, or maybe even derived interface class info. It's a simple indirection, whereas a cast must go through a pointer offset stored in the interface typeinfo in order to get true class info. 3. typeid(i) on one DLL may be different than typeid(i) on another. It is not valid to compare the references directly On 2, see test code: http://dpaste.dzfl.pl/97f5866d -Steve
Jun 24 2013
parent "Lemonfiend" <lemon fie.nd> writes:
On Monday, 24 June 2013 at 15:46:05 UTC, Steven Schveighoffer 
wrote:
 On Sun, 23 Jun 2013 11:29:10 -0400, Lemonfiend <lemon fie.nd> 
 wrote:

 On Sunday, 23 June 2013 at 15:15:16 UTC, Jacob Carlborg wrote:
 On 2013-06-23 13:26, Lemonfiend wrote:
 foreach (I i; array) {
   if (B b = cast(B) i) { ... }
 }
Thanks all 3 of you for the quick and identical answers. :) It had not occurred to me to use a cast for this, but indeed the language ref says the same: "In order to determine if an object o is an instance of a class B use a cast" It does a bit inelegant to me.. Or are casts simply extremely cheap?
You can do something like this as well: if (i.classinfo is B.classinfo) { } But doing the cast is more efficient if you want to use the object of as the type you're checking for.
Using the .classinfo is what I looked at before asking here. However, according to the specs: ".classinfo applied to an interface gives the information for the interface, not the class it might be an instance of." So the i.classinfo and B.classinfo would be different?
1. Use typeid(i), not i.classinfo, classinfo is old-style. 2. Yes, typeid(i) will give you interface class info, or maybe even derived interface class info. It's a simple indirection, whereas a cast must go through a pointer offset stored in the interface typeinfo in order to get true class info. 3. typeid(i) on one DLL may be different than typeid(i) on another. It is not valid to compare the references directly On 2, see test code: http://dpaste.dzfl.pl/97f5866d -Steve
This method would not work for my example, since it would get the interface, not a class. But if I were to maintain an array of some base class instead, it would. Very interesting! Thanks.
Jun 24 2013