3

B. Stroustrup originally designed C++ to not have dynamic_cast but then there was something that people had to add that cast to the language. Wherever I met usage of dynamic_cast it was against polymorphic usage of objects. So it turns sometimes you will prefer to know the object type instead of trying to re-design your code to utilize polymorphism? What cases are those? Can you give even one example?

P.S. Please consider that dynamic_cast adds lots of RTTI info into the code which is partial reflection added to the language as the class hierarchy information is stored in the compiled code. This is against C++ philosophy - you pay for the things you use. (I know you can turn off RTTI but by default it is on and you may not need it in your whole code not a single time!)

EDIT: According to @Griwes's comments turning of RTTI is possible but it is undefined behavior. For this reason the conclusion above related to C++ philosophy becomes much stronger.

Narek
  • 38,779
  • 79
  • 233
  • 389
  • 4
    The "lots of RTTI info" needed for `dynamic_cast` is added because well, `dynamic_cast` needs it. You're paying for what you use. That last paragraph doesn't make sense. – R. Martinho Fernandes Oct 06 '16 at 13:11
  • 4
    I think it's a "business requirement" :) You _need_ to have a way to do quick and dirty hacks. Yesterday the requirement was to hold a huge array of `Animal` objects and make them all `sleep()`. Now customer says let's have `Cat` objects `meow()` first. Now, what's better? To make `Cat` always `meow()` before `sleep()` or just to have `if (dynamic_cast(animals[i]) != NULL)` ... ? :) There you go. – Steeve Oct 06 '16 at 13:14
  • 1
    "instead of trying to re-design your code to utilize polymorphism" - so you're saying that in all cases where `if (auto ptr = dynamic_cast(bar))` is sufficient, I should add a new virtual function to my type? Great. ...oh wait. No C++ open multimethods that don't suck. Oopsie. – Griwes Oct 06 '16 at 13:15
  • 1
    @R.MartinhoFernandes I'm not sure -- isn't RTTI part of the language and thus normally enabled (including the overhead), even when not used in a specific program? I think that's what the OP meant. – Peter - Reinstate Monica Oct 06 '16 at 13:16
  • @OP Disabling RTTI in your program is UB, so no, you can't turn it off. – Griwes Oct 06 '16 at 13:18
  • Also the underlying mechanisms of RTTI are also used by exception handling. – Griwes Oct 06 '16 at 13:18
  • @Griwes what you mean you can't turn it off? http://stackoverflow.com/questions/21400683/whats-the-advantages-of-turning-off-rtti-from-compiler-setting – Narek Oct 06 '16 at 13:19
  • @Griwes Both can be comparatively costly. That's why e.g. embedded systems turn both off, often. It is surely the case that a compiler vendor can define the behavior in this case so that it is not UB (you can argue it is not C++, but that's silly ;-)). – Peter - Reinstate Monica Oct 06 '16 at 13:20
  • @Narek The ISO/IEC 14882 International Standard, that defines what C++ means, says that both exceptions and RTTI must be available in *all* implementations, hence once you disable either, you're no longer writing C++ - or, in other words, it's UB, because UB in essence means exactly that: the behavior of the program is no longer described by the IS. – Griwes Oct 06 '16 at 13:21
  • @PeterA.Schneider The IS defining what C++ is explicitly says that without either it's no longer C++, so no, it's not silly at all. – Griwes Oct 06 '16 at 13:21
  • 1
    @PeterA.Schneider Everything in the language "is part of the language and thus normally enabled". That's a bit tautological. However that doesn't mean that everything has to make it to generated code. – R. Martinho Fernandes Oct 06 '16 at 13:22
  • @R.MartinhoFernandes I just wasn't sure whether the standard makes it an optional feature and couldn't be bothered to look it up. That's why I framed it as a question. – Peter - Reinstate Monica Oct 06 '16 at 13:23
  • Being an optional feature is irrelevant. Look: https://godbolt.org/g/mJRGEj. Neither loops nor increments nor less-than comparisons nor addition are optional. Yet, you're not paying for *any of it*. How come? – R. Martinho Fernandes Oct 06 '16 at 13:24
  • @Narek ^ See above. Your last paragraph still doesn't make sense. – R. Martinho Fernandes Oct 06 '16 at 13:26
  • @R.MartinhoFernandes You properly named the difference between those mandatory features on one side and the equally mandatory RTTI on the other side. That is exactly the OP's motivation to ask this question: You *don't* pay for multiplication if you don't use it; but you *do* pay for RTTI even if you don't use it. That's, as the OP said correctly, against C++'s design principles. (And optimizing it away is often impossible, e.g. across library boundaries.) – Peter - Reinstate Monica Oct 06 '16 at 13:28
  • @PeterA.Schneider you keep repeating this idea: "but you do pay for RTTI even if you don't use it", but without showing evidence. Look, you can pay for multiplication & co as well: https://godbolt.org/g/ftpHBl – R. Martinho Fernandes Oct 06 '16 at 13:30
  • @PeterA.Schneider look, I don't pay the cost even while using it! https://godbolt.org/g/tXtKmt (yes, this is borderline trolling). – Griwes Oct 06 '16 at 13:31
  • 1
    Library boundaries are against C++ design (http://eel.is/c++draft/intro#compliance-2) – R. Martinho Fernandes Oct 06 '16 at 13:33
  • @Griwes You pay a cost comparable to using polymorphic types (on top of that), i.e. you must hold some additional type information. This will be negligible in most cases, just like polymorphism overhead, conceded. (And that the overhead is small is probably the reason RTTI exists.) – Peter - Reinstate Monica Oct 06 '16 at 13:36
  • 1
    @Griwes _" Disabling RTTI in your program is UB"_ Huh?? Where were you taught so? – πάντα ῥεῖ Oct 06 '16 at 13:38
  • @OP Re "According to Griwes's comments turning of RTTI is possible but it is undefined behavior": That's just nonsense. If the vendor permits it, it is most likely well defined. It will not compile programs any longer which use it and thus is not a full C++ compiler, that is all. In that, it will not be alone. – Peter - Reinstate Monica Oct 06 '16 at 13:39
  • @πάνταῥεῖ *per the International Standard*, which is the only sensible way to talk about C++ (and not just one/more of its implementations), if you disable RTTI, it's not C++ anymore. You can find it in the section that describes the differences between the hosted and freestanding modes of a C++ implementation. – Griwes Oct 06 '16 at 13:42
  • @Griwes You can still write perfectly behaving and valid c++ programs without using RTTI. Do you have a cite at hand please? Also did you ever hear about CRTP static polymorphism? – πάντα ῥεῖ Oct 06 '16 at 13:45
  • @Griwes _"RTTI must be available in all implementations"_ That doesn't mean you'll need to use it. Saying that if you disable RTTI is UB or no longer valid c++ is merely nonsense. – πάντα ῥεῖ Oct 06 '16 at 13:48
  • If the question marked is duplicate of my question, should I consider that introduction to the language is BAD and there is no any reasonable use of `dynamic_cast` except the reason @Steeve mentioned related to dirty hacks. – Narek Oct 06 '16 at 13:50
  • @Narek my use case due to the lack of open multimethods is perfectly reasonable. – Griwes Oct 06 '16 at 13:50
  • @Griwes I think I don't know what is Open Multi method and I don't see any example you gave. – Narek Oct 06 '16 at 13:51
  • @πάνταῥεῖ it must be available, regardless of whether you use it or not. Once you disable it, it is not enabled anymore. Hence, once you disable it, you no longer fulfill the requirements of the International Standard that defines what "C++" is. – Griwes Oct 06 '16 at 13:52
  • @Griwes As mentioned this interpretation is simply wrong. – πάντα ῥεῖ Oct 06 '16 at 13:53
  • @Narek A C++ example implementation of the concept is [here](https://github.com/jll63/yomm11), but it's really bad and really, really requires core language facilities. [Here](http://www.stroustrup.com/multimethods.pdf) you can find a paper from Bjarne Stroustrup about the idea. – Griwes Oct 06 '16 at 13:53
  • @πάνταῥεῖ please point a hole in my reasoning. – Griwes Oct 06 '16 at 13:55
  • @πάνταῥεῖ you're not being constructive. You keep repeating "you are wrong" without providing explanation nor evidence, even though you have been presented explanation and evidence already. – R. Martinho Fernandes Oct 06 '16 at 13:56
  • @Griwes I already pointed at your hole a few comments above. That the implementation must be present in a standard conforming c++ compiler doesn't mean that not using that feature or entirely switching it off makes your code UB or invalid c++. – πάντα ῥεῖ Oct 06 '16 at 13:57
  • @πάνταῥεῖ it makes the *implementation* non-compliant. The standard imposes requirements on the behaviour of the implementations (http://eel.is/c++draft/intro#compliance-2). If your point is that some programs only require a subset of a C++ implementation, then that's also a bit tautological and `int main() {}` is the simplest example that makes that point. I.e. the UNIX program `true` is a small enough subset to compile *some* C++ programs; that doesn't make it a C++ compiler. – R. Martinho Fernandes Oct 06 '16 at 13:58
  • Okay, so first of all nobody is claiming that not using a feature creates UB (lol). Second, once you switch off, it's no longer presented to the user, *and the user can detect that*. This is clearly non-conforming. – Griwes Oct 06 '16 at 14:00
  • @R.MartinhoFernandes A program not using RTTI doesn't violate any rule. – πάντα ῥεῖ Oct 06 '16 at 14:00
  • @πάνταῥεῖ you are not reading the evidence you have been presented with. The C++ specification puts requirements on the *implementations*, not on the programs. `int main() {}` doesn't violate any rule either, but that doesn't mean that `true` is a C++ implementation. – R. Martinho Fernandes Oct 06 '16 at 14:01
  • @Griwes _"so first of all nobody is claiming that not using a feature creates UB"_ You did so [here](http://stackoverflow.com/questions/39896772/dynamic-cast-was-introduced-to-c-to-ruin-polymorphism?noredirect=1#comment67079841_39896772) – πάντα ῥεῖ Oct 06 '16 at 14:02
  • @πάνταῥεῖ No I didn't. I said that disabling it is, not that not using it is. I can not use it without disabling it. To end this strawman-filled discussion: as Robot said, the compliance rules are applied to an implementation, not a program. Only well-formedness rules are applied to programs. – Griwes Oct 06 '16 at 14:03
  • @Griwes Well, so all we embedded c++ guys, who switch that feature off, to become rid of the overhead when its not used, are writing non standard conformant code. Interesting. – πάντα ῥεῖ Oct 06 '16 at 14:08
  • @πάνταῥεῖ Well, the code is, but the compiler isn't, even if that's irrelevant. – Peter - Reinstate Monica Oct 06 '16 at 14:09
  • @πάνταῥεῖ somewhat yes (if you count the Makefile or whatever other build system into the total code they are writing). Also there's other reasons for disabling RTTI and exceptions, like not wanting to implement support libraries for your compiler's ABIs, so don't count all `-fno-rtti` on Github as "we don't want the overhead". – Griwes Oct 06 '16 at 14:09
  • @Griwes I once asked a slighly [related question](http://stackoverflow.com/questions/28861760/what-is-the-actual-purpose-of-stdtype-infoname) – πάντα ῥεῖ Oct 06 '16 at 14:12

1 Answers1

0

First of all, RTTI information isn't that big. It includes some information in the read only section of your code, and one additional entry in the virtual table. In that sense, exceptions are much more expensive (actual duplication of some of the generated code which the CPU will never run unless an exception is thrown).

C++'s philosophy is, and has always been, to give you tools you can use to make your code better, but not protect you against bad use of those tools. If you've seen people misuse dynamic cast, that is too bad, but C++ does not consider it a design failure (no more than, say, multiple inheritance).

Personally, I like to use dynamic casts only as asserts. In other words, I build a design where I down cast a class, and I should already know what type I'm down casting to. I then use a dynamic cast to make sure my design isn't broken, and I that this is, indeed, the right type.

The reason this is necessary is because you cannot override a method with a method returning a different return type. If you have A, and B and C inheriting from it, you cannot have A contain:

class A {
...
   virtual A *some_method();
};

And then have:

class B : public A {
...
   override virtual B* some_method();
};

C++ simply does not allow it. Since this is not allowed, it might be necessary to take some_method's return value, and cast it from A* to B*. When you do, it is better to make sure that you do, indeed, have an instance of B in hand, and not, e.g., C.

Shachar Shemesh
  • 8,193
  • 6
  • 25
  • 57
  • 1
    Overriding a method to return child type is OK. Google "virtual functions returning covariant types". Also `override` keyword should could at the end of the function declaration. – Narek Oct 06 '16 at 13:46