digitalmars.D.learn - Dynamic and Static Casting
- d coder (11/11) Feb 10 2011 Greetings All
- Lars T. Kyllingstad (21/32) Feb 10 2011 Here's one solution. I am not 100% sure of the validity of this, so
- Lars T. Kyllingstad (9/24) Feb 10 2011 Ok, bearophile's solution is better, because it has fewer casts. I
- bearophile (56/64) Feb 10 2011 And what about:
- d coder (7/7) Feb 10 2011 Thanks Lars and Bearophile, I will give it a try.
- Steven Schveighoffer (5/10) Feb 10 2011 Be aware that blindly casting interfaces is not a good idea. An interfa...
- spir (19/81) Feb 10 2011 I think so. Definitely need staticDownCast very often for all functional...
- Steven Schveighoffer (3/8) Feb 10 2011 Aren't all upcasts static anyways?
- bearophile (40/48) Feb 10 2011 There is no direct support for it because it's considered bad, so this i...
Greetings All I have learnt that D has only one casting operator and that is 'cast'. The same operator assumes different functionality depending on the context in which it he being used. Now I have a situation where I have to downcast an object and I am sure of the objects type and thereby I am sure that the downcast would only be successful. To make the operation faster, in C++ I could have used static_cast operator, thus giving the RTTI a skip. Would this be possible in D? Can I force a static_cast which downcasting? Regards - Cherry
Feb 10 2011
On Thu, 10 Feb 2011 16:44:12 +0530, d coder wrote:Greetings All I have learnt that D has only one casting operator and that is 'cast'. The same operator assumes different functionality depending on the context in which it he being used. Now I have a situation where I have to downcast an object and I am sure of the objects type and thereby I am sure that the downcast would only be successful. To make the operation faster, in C++ I could have used static_cast operator, thus giving the RTTI a skip. Would this be possible in D? Can I force a static_cast which downcasting?Here's one solution. I am not 100% sure of the validity of this, so until someone else vouches for it, it should be considered evil. It works by first casting the reference to a pointer, then to a different pointer type (which goes unchecked), and then to a reference again. // Evil hack to emulate static_cast T staticCast(T, F)(F from) { return cast(T) cast(T*) cast(F*) from; } Example usage: class A { int i; } class B : A { int j; } void main() { auto b = new B; b.i = 123; auto a = staticCast!A(b); assert (a.i == 123); } -Lars
Feb 10 2011
On Thu, 10 Feb 2011 11:54:02 +0000, Lars T. Kyllingstad wrote:On Thu, 10 Feb 2011 16:44:12 +0530, d coder wrote:Ok, bearophile's solution is better, because it has fewer casts. I forgot you can cast to void*. So here's an improved version, with some template constraints to make sure it's only used for class types: T staticCast(T, U)(U obj) if (is(T == class) && is(U == class)) { return cast(T) cast(void*) obj; } -LarsGreetings All I have learnt that D has only one casting operator and that is 'cast'. The same operator assumes different functionality depending on the context in which it he being used. Now I have a situation where I have to downcast an object and I am sure of the objects type and thereby I am sure that the downcast would only be successful. To make the operation faster, in C++ I could have used static_cast operator, thus giving the RTTI a skip. Would this be possible in D? Can I force a static_cast which downcasting?Here's one solution. [...]
Feb 10 2011
Lars T. Kyllingstad:Ok, bearophile's solution is better, because it has fewer casts.And your solution was better because it's inside a function :-)I forgot you can cast to void*. So here's an improved version, with some template constraints to make sure it's only used for class types: T staticCast(T, U)(U obj) if (is(T == class) && is(U == class)) { return cast(T) cast(void*) obj; }And what about: import std.stdio, std.traits, std.typetuple; /// C++ static_cast for just down-casting T staticDownCast(T, F)(F from) if (is(F == class) && is(T == class) && staticIndexOf!(F, BaseClassesTuple!T) != -1) in { assert((from is null) || cast(T)from !is null); } body { return cast(T)cast(void*)from; } class Foo {} class Bar : Foo {} class Spam {} Bar test1() { Foo f = new Foo; Bar b = cast(Bar)f; return b; } Bar test2() { Foo f = new Foo; Bar b = staticDownCast!Bar(f); return b; } void main() { Spam s = new Spam; Bar b = staticDownCast!Bar(s); // error } /* _D4test5test1FZC4test3Bar comdat L0: push EAX mov EAX,offset FLAT:_D4test3Bar7__ClassZ mov ECX,offset FLAT:_D4test3Foo7__ClassZ push EAX push ECX call near ptr __d_newclass add ESP,4 push EAX call near ptr __d_dynamic_cast add ESP,8 pop ECX ret _D4test5test2FZC4test3Bar comdat L0: push EAX mov EAX,offset FLAT:_D4test3Foo7__ClassZ push EAX call near ptr __d_newclass add ESP,4 pop ECX ret */ Is a pair of similar staticDownCast(), staticUpCast() fit for Phobos? Bye, bearophile
Feb 10 2011
Thanks Lars and Bearophile, I will give it a try. I understand that static downcasting is dangerous. But there are places where efficiency is paramount and you are sure that the casting is safe. So I wholeheartedly second your proposal to have the stuff in phobos. Regards - Cherry
Feb 10 2011
On Thu, 10 Feb 2011 08:02:08 -0500, d coder <dlang.coder gmail.com> wrote:Thanks Lars and Bearophile, I will give it a try. I understand that static downcasting is dangerous. But there are places where efficiency is paramount and you are sure that the casting is safe. So I wholeheartedly second your proposal to have the stuff in phobos.Be aware that blindly casting interfaces is not a good idea. An interface pointer is offset into the object and the cast *must* be dynamic. Casting objects from one class to another should be reliable, however. -Steve
Feb 10 2011
On 02/10/2011 01:38 PM, bearophile wrote:Lars T. Kyllingstad:I think so. Definitely need staticDownCast very often for all functionality in type-hierarchy-generic code where some arguments are known to be of a given subtype. Typically, some func produces a collection of a given supertype (say, Node). It may be stored on a member, or produced on need. Some other func takes such a collection as input; but using this func means we know all or some of the objects are of a given subtype (say AssignmentNode); and indeed, we need the additional members of the subtype. Other case, each Node holds one or more other nodes. In the general case, they can be of any subtype. But when a func takes an AssignmentNode, then it knows its subnodes must be NameNode and ExpressionNode, hey!, ain't it clever? And indeed it'll need to access members specific to their subtypes. But I have never needed upcast in D as of now. What are common use cases? Denis -- _________________ vita es estrany spir.wikidot.comOk, bearophile's solution is better, because it has fewer casts.And your solution was better because it's inside a function :-)I forgot you can cast to void*. So here's an improved version, with some template constraints to make sure it's only used for class types: T staticCast(T, U)(U obj) if (is(T == class)&& is(U == class)) { return cast(T) cast(void*) obj; }And what about: import std.stdio, std.traits, std.typetuple; /// C++ static_cast for just down-casting T staticDownCast(T, F)(F from) if (is(F == class)&& is(T == class)&& staticIndexOf!(F, BaseClassesTuple!T) != -1) in { assert((from is null) || cast(T)from !is null); } body { return cast(T)cast(void*)from; } class Foo {} class Bar : Foo {} class Spam {} Bar test1() { Foo f = new Foo; Bar b = cast(Bar)f; return b; } Bar test2() { Foo f = new Foo; Bar b = staticDownCast!Bar(f); return b; } void main() { Spam s = new Spam; Bar b = staticDownCast!Bar(s); // error } /* _D4test5test1FZC4test3Bar comdat L0: push EAX mov EAX,offset FLAT:_D4test3Bar7__ClassZ mov ECX,offset FLAT:_D4test3Foo7__ClassZ push EAX push ECX call near ptr __d_newclass add ESP,4 push EAX call near ptr __d_dynamic_cast add ESP,8 pop ECX ret _D4test5test2FZC4test3Bar comdat L0: push EAX mov EAX,offset FLAT:_D4test3Foo7__ClassZ push EAX call near ptr __d_newclass add ESP,4 pop ECX ret */ Is a pair of similar staticDownCast(), staticUpCast() fit for Phobos?
Feb 10 2011
On Thu, 10 Feb 2011 11:38:40 -0500, spir <denis.spir gmail.com> wrote:On 02/10/2011 01:38 PM, bearophile wrote:Aren't all upcasts static anyways? -SteveIs a pair of similar staticDownCast(), staticUpCast() fit for Phobos?But I have never needed upcast in D as of now. What are common use cases?
Feb 10 2011
d coder:I have learnt that D has only one casting operator and that is 'cast'. The same operator assumes different functionality depending on the context in which it he being used.Walter likes this design, I presume he thinks it's simpler.Now I have a situation where I have to downcast an object and I am sure of the objects type and thereby I am sure that the downcast would only be successful. To make the operation faster, in C++ I could have used static_cast operator, thus giving the RTTI a skip. Would this be possible in D? Can I force a static_cast which downcasting?There is no direct support for it because it's considered bad, so this is usually not done in D, it's for special situations only: class Foo {} class Bar : Foo {} Bar test1() { Foo f = new Foo; Bar b = cast(Bar)f; return b; } Bar test2() { Foo f = new Foo; Bar b = cast(Bar)cast(void*)f; return b; } void main() {} DMD 2.051, -O -release -inline: _D4test5test1FZC4test3Bar comdat L0: push EAX mov EAX,offset FLAT:_D4test3Bar7__ClassZ mov ECX,offset FLAT:_D4test3Foo7__ClassZ push EAX push ECX call near ptr __d_newclass add ESP,4 push EAX call near ptr __d_dynamic_cast add ESP,8 pop ECX ret _D4test5test2FZC4test3Bar comdat L0: push EAX mov EAX,offset FLAT:_D4test3Foo7__ClassZ push EAX call near ptr __d_newclass add ESP,4 pop ECX ret Bye, bearophile
Feb 10 2011