digitalmars.D - rtti cast
↑ ↓ ← → 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();
}
↑ ↓ ← → 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();
↑ ↓ ← → 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.
↑ ↓ ← → 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????
↑ ↓ ← → 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);
}
↑ ↓ ← → 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?
↑ ↓ ← → 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.
↑ ↓ ← → 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?
↑ ↓ ← → 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);
}
}
↑ ↓ ← → "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.
↑ ↓ ← → 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
↑ ↓ ← → 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)
{
// ...
}
}
↑ ↓ ← → 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
|