www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - rtti cast

reply Simon Buerger <krox gmx.net> writes:
hi
I would like to do some RTTI, but not with type-IDs, but in some more 
pretty way. I'll simply post some code to show you what I mean :) . My 
Question is now: Does anyone know, how to do sth alike with the 
current D implementation (maybe with templates, but I dont see a nice 
way) ? Or do you think it could be worth an extension for D 2.0 ?
Krox

Code:

class Base {}
class A : Base
{
	void function_A() { ... }
}
class B : Base {}
{
	void function_B() { ... }
}

void main()
{
	Base x = ...
	
	// checks if x is of type A, and if so, declares y as A alias of x 
with other type
	if (x == A y)	
		y.function_A();
	else if(x == B y)
		y.function_B();
}
May 01 2008
parent reply BCS <BCS pathlink.com> writes:
Simon Buerger wrote:
 hi
 I would like to do some RTTI, but not with type-IDs, but in some more 
 pretty way. I'll simply post some code to show you what I mean :) . My 
 Question is now: Does anyone know, how to do sth alike with the current 
 D implementation (maybe with templates, but I dont see a nice way) ? Or 
 do you think it could be worth an extension for D 2.0 ?
 Krox
 
 Code:
 
 class Base {}
 class A : Base
 {
     void function_A() { ... }
 }
 class B : Base {}
 {
     void function_B() { ... }
 }
 
 void main()
 {
     Base x = ...
     
     // checks if x is of type A, and if so, declares y as A alias of x 
 with other type
     if (x == A y)   
         y.function_A();
     else if(x == B y)
         y.function_B();
 }

this work? if (auto y = cast(A)x) y.function_A(); else if(auto y = cast(B)x) y.function_B();
May 01 2008
parent reply Simon Buerger <krox gmx.net> writes:
BCS wrote:
 this work?
 
 if (auto y = cast(A)x)
     y.function_A();
 else if(auto y = cast(B)x)
     y.function_B();
 

Well, honestly I'm really impressed. Thats perfectly what I wanted. Seems to be standard, but I didn't knew about it *lolz*. Okay, seems to be solved then. Thanks.
May 01 2008
parent reply terranium <spam here.lot> writes:
Simon Buerger Wrote:

 BCS wrote:
 this work?
 
 if (auto y = cast(A)x)
     y.function_A();
 else if(auto y = cast(B)x)
     y.function_B();
 

Well, honestly I'm really impressed. Thats perfectly what I wanted. Seems to be standard, but I didn't knew about it *lolz*. Okay, seems to be solved then. Thanks.

OMG invalid cast doesn't throw exception????
May 02 2008
parent reply Pragma <eric.t.anderton gmail.com> writes:
terranium Wrote:

 Simon Buerger Wrote:
 
 BCS wrote:
 this work?
 
 if (auto y = cast(A)x)
     y.function_A();
 else if(auto y = cast(B)x)
     y.function_B();
 

Well, honestly I'm really impressed. Thats perfectly what I wanted. Seems to be standard, but I didn't knew about it *lolz*. Okay, seems to be solved then. Thanks.

OMG invalid cast doesn't throw exception????

Nope. Invalid casts simply return null. If you absolutely need an exception, then you can just wrap the cast in a templated function: class DynamicCastException : Exception{ public this(char[] reason){ super(reason); } } T dyn_cast(T)(Object x){ T result = cast(T)x; if(result is null) throw new DynamicCastException("Cannot cast to type " ~ T.stringof); return result; } class A{} class B:A{} class C{} void main(){ B x = new B(); C y = dyn_cast!(C)(x); }
May 02 2008
parent reply terranium <spam here.lot> writes:
Pragma Wrote:

 If you absolutely need an exception

And who don't? Yet another D misdesign to be worked around? And where will be more legacy design typos in the end? In C++ or in D?
May 02 2008
next sibling parent reply BCS <BCS pathlink.com> writes:
terranium wrote:
 Pragma Wrote:
 
 
If you absolutely need an exception

And who don't? Yet another D misdesign to be worked around? And where will be more legacy design typos in the end? In C++ or in D?

In most cases forgetting to check the cast return will result in an seg-v from a dereferenced null because you almost always use it as the very next thing. Also it will never result in a miss use for the same reason, the pointer doesn't point to anything. Having the "bad cast" -> null is very handy when you don't known if the cast will be good. It mean you can test it without invoking the exception system and all the overhead that entails.
May 02 2008
parent reply terranium <spam here.lot> writes:
BCS Wrote:

 In most cases forgetting to check the cast return will result in an 
 seg-v from a dereferenced null because you almost always use it as the 

In most cases... almost always... When an invalid cast occurs, the error is not in null pointer it's in invalid cast, and replacing InvalidCastException with a hope for NullPointerException is a wrong way.
 Having the "bad cast" -> null is very handy when you don't known if the 
 cast will be good. It mean you can test it without invoking the 
 exception system and all the overhead that entails.

maybe in this case we need some syntax sugar, not a silent cast?
May 07 2008
parent BCS <BCS pathlink.com> writes:
terranium wrote:
 BCS Wrote:
 
 
In most cases forgetting to check the cast return will result in an 
seg-v from a dereferenced null because you almost always use it as the 

In most cases... almost always... When an invalid cast occurs,

it is not an error. Thinking about it, I can't recall ever casting to a derived type where a failed cast was an indication of a bug. In the few times I have done it, it has always been in the context of "if a is'a B then" (and not just in the code but in the proper function of the program as well).
Having the "bad cast" -> null is very handy when you don't known if the 
cast will be good. It mean you can test it without invoking the 
exception system and all the overhead that entails.

maybe in this case we need some syntax sugar, not a silent cast?

a little sugar for the other way might be even handier // not tested template Force_Cast(T) { T Force_Cast(U)(U u) { static assert(is(U : T), "cant cast from " ~ U.stringof ~ " to " ~ T.stringof); if(auto t = cast(T)u) return t; else throw new InvalidCastException("failed cast from " ~ U.stringof ~ " to " ~ T.stringof); } }
May 07 2008
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"terranium" <spam here.lot> wrote in message 
news:fvf93j$194u$1 digitalmars.com...
 Pragma Wrote:

 If you absolutely need an exception

And who don't?

I don't. I perform downcasts extremely rarely. When I do, it's usually in code like: if(auto y = cast(Y)x) ... else // not a Y, try something else That is, the code is only executed if the cast succeeds. Furthermore, it's a lot easier and more efficient to have the cast return null and throw an exception _only if needed_ than to throw an exception and then have to catch it: try { auto y = cast(Y)x; ... } catch(CastException e) { // not a Y, try something else.. } For that matter, some languages (like C#) have both kinds of casts - one that throws an exception and one that doesn't. Either can really be implemented in the other, but the null-returning kind is more basic and efficient.
May 02 2008
parent Leandro Lucarella <llucax gmail.com> writes:
Jarrett Billingsley, el  2 de mayo a las 16:40 me escribiste:
 For that matter, some languages (like C#) have both kinds of casts - one 
 that throws an exception and one that doesn't.  Either can really be 
 implemented in the other, but the null-returning kind is more basic and 
 efficient. 

C++ have the 2 too. If you cast a pointer, it returns NULL if the cast fails but if you cast a reference, the cast throws a bad_cast exception if it fails. Unfortunatelly this can't be done in D (at least in an elegant way) because it's reference semantics for objects. But I thinks std.contracts.enforce[1] is a perfect solution for this: auto y = enforce(cast(D)x); // y is not null from here on Or just use assert if you want the check to be gone in release builds: auto y = cast(D)x; assert(y !is null); [1] http://www.digitalmars.com/d/2.0/phobos/std_contracts.html -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- The number of wars fought between countries That both have at least one McDonalds is zero
May 05 2008
prev sibling next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
terranium wrote:
 Pragma Wrote:
 
 If you absolutely need an exception

And who don't? Yet another D misdesign to be worked around? And where will be more legacy design typos in the end? In C++ or in D?

In Java, I often find myself writing code like: void process(Object o) { if(o instanceof String) { String s = (String) o; // ... } else if(o instanceof List) { List<String> l = (List<String>) o; // ... } } It's much easier (and more efficient) to use the D way: void process(Object o) { if(auto s = cast(string) o) { //... } else if(auto l = cast(Seq!(string) o) { // ... } }
May 02 2008
prev sibling parent downs <default_357-line yahoo.de> writes:
terranium wrote:
 Pragma Wrote:
 
 If you absolutely need an exception

And who don't? Yet another D misdesign to be worked around? And where will be more legacy design typos in the end? In C++ or in D?

Actually, since you don't know if the cast is really valid, it failing is a regular outcome. As such, an exception (which is reserved, appropriately, for *exceptional* events), is totally the wrong approach to use. Note that with the current behavior, you can incur the runtime speed loss of throwing an exception if you _want_ to, by using the above templated wrapper, but if throwing an exception were the only possibility, you couldn't possibly get that speed back. So it really is better this way. :) --downs
May 03 2008