On Mar 5, 3:05 pm, Andy Champ <no....@nospam.com> wrote:
> How many times have you written
> someType* var = dynamic_cast<someType*>(someOtherPtr);
> and wondered WTH you have to quote the type twice?
The C++ cast operators, including dynamic_cast<>, were deliberately designed to have an unwieldy syntax precisely to discourage C++ programmers from using them. Why, after all, does a program need to perform a downcast to someType? Either "SomeOtherPtr" should have been a pointer to a someType object all along - or class-specific behavior that the client needs should have been modeled inside the class implementation itself.
Micah Cowan wrote: > Andy Champ <no....@nospam.com> writes:
>> Daniel T. wrote: >>> Andy Champ <no....@nospam.com> wrote:
>>>> How many times have you written
>>>> someType* var = dynamic_cast<someType*>(someOtherPtr); >>> In professional code? Never. >> Why not?
> Because it pretty much always indicates a design flaw. Polymorphism is > the preferred idiom.
> Of course, sometimes design flaws are unavoidable, particularly when > not all the code involved is under your control.
In my case, it isn't the code, it's the data structures that the objects/classes represent that triggered off me doing this so much.
However, in the general case where you have classes that exhibit very similar behaviour you are going to want to treat them the same most of the time, calling common interfaces. Just occasionally you want to know which of the specialised classes you have, in order to invoke the specialised behaviour. That's when dynamic_cast comes in.
Greg Herlihy wrote:
> The C++ cast operators, including dynamic_cast<>, were deliberately > designed to have an unwieldy syntax precisely to discourage C++ > programmers from using them. Why, after all, does a program need to > perform a downcast to someType? Either "SomeOtherPtr" should have been > a pointer to a someType object all along - or class-specific behavior > that the client needs should have been modeled inside the class > implementation itself. > > Greg
I'd love to see a reference on that. I'm guessing it was just easier for the compiler designers not to have to affect the right side with the object on the left side of the operator.
With a raw pointer, this works fine. If the object on the LHS has multiple constructors I can imagine the compiler getting a bit confused - which is another reason for keeping the traditional, clumsy, syntax at least some of the time, as it *forces* the type of conversion.
Without templates, you can't do my trick, and templates are a late addition to the language.
Andy Champ <no....@nospam.com> wrote: > Daniel T. wrote: > > Andy Champ <no....@nospam.com> wrote:
> > > How many times have you written
> > > someType* var = dynamic_cast<someType*>(someOtherPtr);
> > In professional code? Never.
> Why not?
Because I program using OO idioms, not representational ones. Or to put it another way, I specifically design my programs such that I don't need to use dynamic_cast... even occasionally.
Micah Cowan wrote: > Andy Champ <no....@nospam.com> writes:
>> Daniel T. wrote: >>> Andy Champ <no....@nospam.com> wrote:
>>>> How many times have you written
>>>> someType* var = dynamic_cast<someType*>(someOtherPtr); >>> In professional code? Never. >> Why not?
> Because it pretty much always indicates a design flaw. Polymorphism is > the preferred idiom.
I think there are a few cases where trying to avoid dynamic_cast at all costs becomes counter-productive, and the code would only get uglier.
For example, let's assume you have some kind of primitive manager which can contain all types of primitives (ie. it contains pointers to objects derived from some 'Primitive' base class).
For the user to be able to perform some operations to those primitives when the manager so requests, there are basically two options: The manager either calls a virtual function defined in the 'Primitive' base class (which the derived classes can implement), or the manager calls a callback function given to it by the user, giving this callback function a reference/pointer to the object (this reference/pointer has to be of type 'Primitive', of course, because the actual object can be of any type).
The first option would be the nicest, but it becomes awkward in some cases. For example, if the operation to be performed requires something the object itself cannot do. This would mean that the object would have to have a pointer to the actual module which can do that operation, and it has to call a function through that pointer, and it has to have permission to do so (the function must be public, or the object must be a friend of the module). This also means you can't have pre-made primitives (eg. provided by the same library which provides the primitive manager) which can simply be instantiated and given to the manager. At the very least you will have to create your own class derived from this pre-made primitive, and in it you will have to implement the store-pointer-call-function functionality. This may quickly become laborious if you want to use lots of different pre-made primitives.
The other alternative is to use the callback mechanism and dynamic_cast, for example like this:
void MyClass::doSomethingToPrimitive(Primitive* p) { Circle* c = dynamic_cast<Circle*>(p); if(c) { // Do something to the circle }
}
Ugly? Maybe. But IMO less ugly, and especially less laborious than the first option.
The usual reason to avoid dynamic_cast is that it can fail: This happens if the object behind the pointer is not of the type being casted to. However, in this case this is not a problem at all, and in fact part of the very functionality of the system: The dynamic_cast is actually a "check" to see if the given object was of a certain type (and if it was, then some operation is done to it).
Sure, with many objects you end up with a large amount of dynamic casts and if-blocks, but the alternative is not any less laborious. One could even argue that the alternative is less readable because the actual functionality is dispersed and not concisely located at one place. It all depends on the actual situation, I suppose.
Greg Herlihy wrote: > On Mar 5, 3:05 pm, Andy Champ <no....@nospam.com> wrote: >> How many times have you written
>> someType* var = dynamic_cast<someType*>(someOtherPtr);
>> and wondered WTH you have to quote the type twice?
> The C++ cast operators, including dynamic_cast<>, were deliberately > designed to have an unwieldy syntax precisely to discourage C++ > programmers from using them.
Do you have any reference to corroborate this?
One could argue that the different casts were made keywords to help making the code more readable (and make it easier to, for example, find the places where a certain type of cast is being done).
> Greg Herlihy wrote: >> On Mar 5, 3:05 pm, Andy Champ <no....@nospam.com> wrote: >>> How many times have you written
>>> someType* var = dynamic_cast<someType*>(someOtherPtr);
>>> and wondered WTH you have to quote the type twice? >> The C++ cast operators, including dynamic_cast<>, were deliberately >> designed to have an unwieldy syntax precisely to discourage C++ >> programmers from using them.
> Do you have any reference to corroborate this?
I guess it is one of those urban legend.
> One could argue that the different casts were made keywords to help > making the code more readable (and make it easier to, for example, find > the places where a certain type of cast is being done).
IMO you are right.
The cast the most likely to be used is the static_cast<> and it is not used that much: mainly when the implicit cast is dangerous or ambiguous.
The const_cast<> and reinterpret_cast<> can yield UB unless used with care and dynamic_cast<> is so seldom used that it is surprising to see it.
> Ugly? Maybe. But IMO less ugly, and especially less laborious > than the first option.
Agreed. If those were our only two options, then you are 100% correct. Fortunately, there are other options. This is exactly why OO books warn against "manager" objects.
On Mar 7, 10:37 am, Juha Nieminen <nos...@thanks.invalid> wrote:
> Daniel T. wrote: > > Agreed. If those were our only two options, then you are 100% correct. > > Fortunately, there are other options.
> Thanks for not giving even a hint of these other options and were to > find more info about them.
You didn't provide a requirements document so I can't give any hint of what the hundereds of other design possibilities might be.
Instead you presented one spicific design that had a spicific problem, and showed how dynamic_cast can fix the problem. I'm simply saying that if you don't design your code like that in the first place, you won't have the problem presented, and therefore won't need dynamic_cast to fix it.
Michael DOUBEZ wrote: > Juha Nieminen a écrit : >> Greg Herlihy wrote: >>> On Mar 5, 3:05 pm, Andy Champ <no....@nospam.com> wrote: >>>> How many times have you written
>>>> someType* var = dynamic_cast<someType*>(someOtherPtr);
>>>> and wondered WTH you have to quote the type twice? >>> The C++ cast operators, including dynamic_cast<>, were deliberately >>> designed to have an unwieldy syntax precisely to discourage C++ >>> programmers from using them.
"An ugly operation should have an ugly syntactic form."
>> One could argue that the different casts were made keywords to help >> making the code more readable (and make it easier to, for example, find >> the places where a certain type of cast is being done).
> IMO you are right.
> The cast the most likely to be used is the static_cast<> and it is not > used that much: mainly when the implicit cast is dangerous or ambiguous.
> The const_cast<> and reinterpret_cast<> can yield UB unless used with > care and dynamic_cast<> is so seldom used that it is surprising to see it.
I see dynamic_cast all the time. The ensuing conversation between me and the original coder usually is something like this:
<conversation> Coder: "I'm dynamically allocating a sequence of objects, each of which may be of any of ten different types D0-D9, all implementing a common run-time interface B (base class with virtual methods). I allocate the objects with operator new, and store pointers to them in a monolothic collection of pointers-to-B. If I later need all the objects of type D1, I walk the list and dynamic cast every single element to find out whether it's of type D1."
Me: "Why not store ten different collections for D0-D9? They would be statically type-safe."
Coder: "Usually, I have to work with all the objects, and I don't want to have to traverse ten different collections."
Me (ashamed to be encouraging premature optimization): "Dynamic cast is slow."
Coder: "Ten lists have more overhead than one list. It's a trade-off."
Me: "You're not letting the compiler help you."
Coder: "I don't need the compiler's help here. The run-time environment does what I need. Why should I go out of my way to get the compiler's approval? I've been doing this for ## years. I know what I'm doing."
Me: (Thinks about explaining the manifold potential safety and performance blessings that come from moving computation to compile-time, and danger of violating an excellent rule of thumb for no good reason. Decides it's not worth further irritating Coder.) OK, thanks very much for going over that with me. I appreciate your time.
</conversation>
In the end, I just request that there be documented APIs between different parts of the code, so that I will have a decent shot at figuring out who's code is causing the bugs I know we'll be seeing soon. Even that is an up-hill battle, but modularity is lower-hanging fruit than compile-time safety. I think programmers just continue to believe whatever they were told by their Computer Science professors, without ever really thinking for themselves; "modularity" makes the list of things covered in typical undergraduate courses, but "static type safety" does not. What really irritates me is that kids coming out of school seem to have even less appreciation for static type safety than the old-timers, so there's not a whole lot of hope in sight. The Python community in particular seems to believe static typing is about as obsolete as magnetic core memory. It's depressing.
On Mar 6, 3:23 pm, Andy Champ <no....@nospam.com> wrote:
> Greg Herlihy wrote:
> > The C++ cast operators, including dynamic_cast<>, were deliberately > > designed to have an unwieldy syntax precisely to discourage C++ > > programmers from using them. Why, after all, does a program need to > > perform a downcast to someType? Either "SomeOtherPtr" should have been > > a pointer to a someType object all along - or class-specific behavior > > that the client needs should have been modeled inside the class > > implementation itself. > > > > Greg
> I'd love to see a reference on that. I'm guessing it was just easier > for the compiler designers not to have to affect the right side with the > object on the left side of the operator.
For a reference, please see this Bjarne Stroustrup post to comp.std.c+ + (and which also contains a link to his C++ faq):
Daniel T. wrote: > Andy Champ <no....@nospam.com> wrote: >> Daniel T. wrote: >>> Andy Champ <no....@nospam.com> wrote:
>>>> How many times have you written
>>>> someType* var = dynamic_cast<someType*>(someOtherPtr); >>> In professional code? Never. >> Why not?
> Because I program using OO idioms, not representational ones. Or to put > it another way, I specifically design my programs such that I don't need > to use dynamic_cast... even occasionally.
There are occasions when the interface forces your hand. For example when implementing the W3C Document Object Model, where all of the container types are collections of the the base object (Node). Node is seldom used, most containers end up storing derived objects (Elements or Attributes) that extend the functionality of Node.
On Mar 7, 2:58 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> Daniel T. wrote:
> > Because I program using OO idioms, not representational ones. Or to put > > it another way, I specifically design my programs such that I don't need > > to use dynamic_cast... even occasionally.
> There are occasions when the interface forces your hand. For example > when implementing the W3C Document Object Model, where all of the > container types are collections of the the base object (Node). Node is > seldom used, most containers end up storing derived objects (Elements or > Attributes) that extend the functionality of Node.
All I can say to that is that I have never had my hand forced. :-) The question with the above is, do you know statically (i.e., at compile time) the types of the objects? Even with generic containers like you mention, if you only put in objects of type X, then you know that all objects in the container are of type X.
Daniel T. wrote: > On Mar 7, 2:58 pm, Ian Collins <ian-n...@hotmail.com> wrote: >> Daniel T. wrote:
>>> Because I program using OO idioms, not representational ones. Or to put >>> it another way, I specifically design my programs such that I don't need >>> to use dynamic_cast... even occasionally. >> There are occasions when the interface forces your hand. For example >> when implementing the W3C Document Object Model, where all of the >> container types are collections of the the base object (Node). Node is >> seldom used, most containers end up storing derived objects (Elements or >> Attributes) that extend the functionality of Node.
> All I can say to that is that I have never had my hand forced. :-) The > question with the above is, do you know statically (i.e., at compile > time) the types of the objects? Even with generic containers like you > mention, if you only put in objects of type X, then you know that all > objects in the container are of type X.
No, that's the nasty bit.
Say you have an element type with an attribute you want to use (the link in an XHTML anchor element for instance) and you wish to process all of these elements in a document. The DOM interface provides a means of extracting a list of them by name, but that list is a list of Nodes and Node doesn't even have attributes!
and let the library do the conversion from Node to Anchor under the hood. One benefit of using dynamic_cast is the conversion will fail if the Node isn't the expected type.
> Daniel T. wrote: > > On Mar 7, 2:58 pm, Ian Collins <ian-n...@hotmail.com> wrote: > >> Daniel T. wrote:
> >>> Because I program using OO idioms, not representational ones. Or to put > >>> it another way, I specifically design my programs such that I don't need > >>> to use dynamic_cast... even occasionally. > >> There are occasions when the interface forces your hand. For example > >> when implementing the W3C Document Object Model, where all of the > >> container types are collections of the the base object (Node). Node is > >> seldom used, most containers end up storing derived objects (Elements or > >> Attributes) that extend the functionality of Node.
> > All I can say to that is that I have never had my hand forced. :-) The > > question with the above is, do you know statically (i.e., at compile > > time) the types of the objects? Even with generic containers like you > > mention, if you only put in objects of type X, then you know that all > > objects in the container are of type X.
> No, that's the nasty bit.
> Say you have an element type with an attribute you want to use (the link > in an XHTML anchor element for instance) and you wish to process all of > these elements in a document. The DOM interface provides a means of > extracting a list of them by name, but that list is a list of Nodes and > Node doesn't even have attributes!
> and let the library do the conversion from Node to Anchor under the > hood. One benefit of using dynamic_cast is the conversion will fail if > the Node isn't the expected type.
I will be happy to grant that if you are coding in a representational style instead of Object Oriented, you may very well have to use dynamic_cast. I don't code that way, nor do any of the libraries I use.
Jeff Schwab wrote: > [...] > <conversation> > Coder: "I'm dynamically allocating a sequence of objects, each of which > may be of any of ten different types D0-D9, all implementing a common > run-time interface B (base class with virtual methods). I allocate the > objects with operator new, and store pointers to them in a monolothic > collection of pointers-to-B. If I later need all the objects of type > D1, I walk the list and dynamic cast every single element to find out > whether it's of type D1."
:-o
That being said, I wonder if there is a technical reason why const static virtual member variables are not allowed. For example, this does not compile:
class base { public: int i; virtual static const enum types { type_base = 0, type_1, type_2, type_3, type_n } id = type_base;
};
class sub1 : public base { static const types type = type_1;
};
But why, I ask you, should the vtable only contain method pointers? The one problem I see in syntactical: Is the following a pure virtual member or a member initialised to 0: class c { virtual static const int i = 0; };
Daniel T. wrote: > On Mar 7, 3:40 pm, Ian Collins <ian-n...@hotmail.com> wrote: >>> On Mar 7, 2:58 pm, Ian Collins <ian-n...@hotmail.com> wrote: >>>> There are occasions when the interface forces your hand. For example >>>> when implementing the W3C Document Object Model, where all of the >>>> container types are collections of the the base object (Node). Node is >>>> seldom used, most containers end up storing derived objects (Elements or >>>> Attributes) that extend the functionality of Node.
>> Say you have an element type with an attribute you want to use (the link >> in an XHTML anchor element for instance) and you wish to process all of >> these elements in a document. The DOM interface provides a means of >> extracting a list of them by name, but that list is a list of Nodes and >> Node doesn't even have attributes!
>> and let the library do the conversion from Node to Anchor under the >> hood. One benefit of using dynamic_cast is the conversion will fail if >> the Node isn't the expected type.
> I will be happy to grant that if you are coding in a representational > style instead of Object Oriented, you may very well have to use > dynamic_cast. I don't code that way, nor do any of the libraries I > use.
OK, given an interface with the restrictions I mentioned above, how would you code it in an "OO" style?
Daniel T. wrote: > On Mar 7, 10:37 am, Juha Nieminen <nos...@thanks.invalid> wrote: >> Daniel T. wrote:
>>> Agreed. If those were our only two options, then you are 100% correct. >>> Fortunately, there are other options. >> Thanks for not giving even a hint of these other options and were to >> find more info about them.
> You didn't provide a requirements document so I can't give any hint of > what the hundereds of other design possibilities might be.
> Instead you presented one spicific design that had a spicific problem, > and showed how dynamic_cast can fix the problem. I'm simply saying > that if you don't design your code like that in the first place, you > won't have the problem presented, and therefore won't need > dynamic_cast to fix it.
Daniel,
if the base class does not have an interface that exhibits the enhanced behaviour, and if the base class is not under your control (hence cannot be enhanced to add the new interface) you have no choice but to use dynamic_cast to determine whether your object exhibits the behaviour you require.
I'd be interested to know how many projects you have worked on that you've never had to break the ideal design of the language, just to get something done.
Ian Collins <ian-n...@hotmail.com> wrote: > Daniel T. wrote: > > On Mar 7, 3:40 pm, Ian Collins <ian-n...@hotmail.com> wrote: > >>> On Mar 7, 2:58 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> >>>> There are occasions when the interface forces your hand. For example > >>>> when implementing the W3C Document Object Model, where all of the > >>>> container types are collections of the the base object (Node). Node is > >>>> seldom used, most containers end up storing derived objects (Elements or > >>>> Attributes) that extend the functionality of Node.
> >> Say you have an element type with an attribute you want to use (the link > >> in an XHTML anchor element for instance) and you wish to process all of > >> these elements in a document. The DOM interface provides a means of > >> extracting a list of them by name, but that list is a list of Nodes and > >> Node doesn't even have attributes!
> >> and let the library do the conversion from Node to Anchor under the > >> hood. One benefit of using dynamic_cast is the conversion will fail if > >> the Node isn't the expected type.
> > I will be happy to grant that if you are coding in a representational > > style instead of Object Oriented, you may very well have to use > > dynamic_cast. I don't code that way, nor do any of the libraries I > > use.
> OK, given an interface with the restrictions I mentioned above, how > would you code it in an "OO" style?
If I was forced to use an interface with the restrictions you mention, then I couldn't code in an OO style. So I'm not sure how to answer your question.
Daniel T. wrote: > Ian Collins <ian-n...@hotmail.com> wrote: >> OK, given an interface with the restrictions I mentioned above, how >> would you code it in an "OO" style?
> If I was forced to use an interface with the restrictions you mention, > then I couldn't code in an OO style. So I'm not sure how to answer your > question.
So your original contention
"Because I program using OO idioms, not representational ones. Or to put it another way, I specifically design my programs such that I don't need to use dynamic_cast... even occasionally."
Andy Champ <no....@nospam.com> wrote: > Daniel T. wrote: > > Juha Nieminen <nos...@thanks.invalid> wrote: > > > Daniel T. wrote:
> > > > Agreed. If those were our only two options, then you are 100% > > > > correct. Fortunately, there are other options.
> > > Thanks for not giving even a hint of these other options and > > > were to find more info about them.
> > You didn't provide a requirements document so I can't give any > > hint of what the hundereds of other design possibilities might > > be.
> > Instead you presented one spicific design that had a spicific > > problem, and showed how dynamic_cast can fix the problem. I'm > > simply saying that if you don't design your code like that in the > > first place, you won't have the problem presented, and therefore > > won't need dynamic_cast to fix it.
> if the base class does not have an interface that exhibits the > enhanced behaviour, and if the base class is not under your control > (hence cannot be enhanced to add the new interface) you have no > choice but to use dynamic_cast to determine whether your object > exhibits the behaviour you require.
Unless the part of the program that is creating the objects is *also* out of your control, and it is dumping the static information about the object's type, you are not required to use dynamic_cast. Such a design is, IMHO sub-standard.
Have you ever noticed all the arrows in UML diagrams? Arrows leading from users to that which is used? 'dynamic_cast' goes against those arrows.
> I'd be interested to know how many projects you have worked on that > you've never had to break the ideal design of the language, just to > get something done.
And I'd be interested to know how few projects you worked on before you started breaking ideal design principles willy nilly. (I'm *kidding*! :-)
Seriously though, I've been programming professionally in C++ since 1998 and have credit in the release of over a dozen titles. For many of them I was involved in the design of the framework that other team members relied on. I am currently the most senior developer at my job, and so often find myself as the chief code reviewer and example setter. I.E., I can't afford to break the rules of good design without loosing credibility. :-)
If you feel you absolutely must use dynamic_cast in a particular situation, by all means do so. The OP asked how many times have I used it, and the answer is never in professional code. I, of course, have used it when helping others learn its mechanics, toy programs and tutorials...