Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Why RTTI is considered as a bad design? (http://www.velocityreviews.com/forums/t948907-why-rtti-is-considered-as-a-bad-design.html)

davidkevin@o2.pl 08-01-2012 08:23 AM

Why RTTI is considered as a bad design?
 
Hi,
what is a reason for which RTTI is considered as a bad design?
Stroustrup has written in his book TC++PL that the most common case of usage RTTI technique is with switch instruction, when one want to decide what code should be executed basing on what is a "real" type of a passed object. There is given an example in which an object of shape class was passed to the function and different actions were executed depending on that whether a shape is circle, square, triangle, etc. He has written that such construction is a sign that one should replace the switch-case sequence by virtual functions.

In my opinion such dealing is reasonable if what should be done is really amatter of given type (for example counting the area of circle).

But is RTTI design undesirable in the situation in which a choice of actiondepends upon how an external module want to treat objects basing on types of them?

For example if one is making a space-war game in which there are many kindsof ships usage of RTTI seems quite logical to me.



Marcel MŘller 08-01-2012 08:38 AM

Re: Why RTTI is considered as a bad design?
 
On 01.08.2012 10:23, davidkevin@o2.pl wrote:
> what is a reason for which RTTI is considered as a bad design?
> Stroustrup has written in his book TC++PL that the most common case of usage RTTI technique is with switch instruction, when one want to decide what code should be executed basing on what is a "real" type of a passed object. There is given an example in which an object of shape class was passed to the function and different actions were executed depending on that whether a shape is circle, square, triangle, etc. He has written that such construction is a sign that one should replace the switch-case sequence by virtual functions.


Well, this is not always possible. Think of multiple dispatch for instance.

> But is RTTI design undesirable in the situation in which a choice of action depends upon how an external module want to treat objects basing on types of them?
>
> For example if one is making a space-war game in which there are many kinds of ships usage of RTTI seems quite logical to me.


I don't see directly why RTTI should help here. But if you refer to
interaction between different types of ships, the yes, this is again a
multiple dispatch problem.


Marcel

Alain Ketterlin 08-01-2012 08:57 AM

Re: Why RTTI is considered as a bad design?
 
davidkevin@o2.pl writes:

> what is a reason for which RTTI is considered as a bad design?
> Stroustrup has written in his book TC++PL that the most common case of
> usage RTTI technique is with switch instruction, when one want to
> decide what code should be executed basing on what is a "real" type of
> a passed object. There is given an example in which an object of shape
> class was passed to the function and different actions were executed
> depending on that whether a shape is circle, square, triangle, etc. He
> has written that such construction is a sign that one should replace
> the switch-case sequence by virtual functions.
>
> In my opinion such dealing is reasonable if what should be done is
> really a matter of given type (for example counting the area of
> circle).


Using class/inheritance/virtual functions provides static information
(used by the compiler). RTTI is, well, run-time.

Suppose you add a new shape sub-class in your example. Using RTTI, the
compiler will be unable to tell you that you forgot to add the
corresponding case in your switch. If you use virtual functions, the
compiler will tell you that your new class fails to implement the
function.

> But is RTTI design undesirable in the situation in which a choice of
> action depends upon how an external module want to treat objects
> basing on types of them?


I can't parse your remark here. If you mean that an external module may
need dynamic type information on your objects to be able to handle them
properly, then why not provide the correct functions in your own
classes?

> For example if one is making a space-war game in which there are many
> kinds of ships usage of RTTI seems quite logical to me.


How can you be sure all kinds of ships are correctly handled by all of
your code? You can't. You have to manually inspect all switches.

-- Alain.

davidkevin@o2.pl 08-01-2012 12:25 PM

Re: Why RTTI is considered as a bad design?
 
W dniu ┼Ťroda, 1 sierpnia 2012 10:57:06 UTC+2 u┼╝ytkownik Alain Ketterlin napisa┼é:
> davidkevin@o2.pl writes:
> I can't parse your remark here. If you mean that an external module may
> need dynamic type information on your objects to be able to handle them
> properly, then why not provide the correct functions in your own
> classes?


Because such representation could be completely inconsistent with a problemwe
are trying to solve. If we assume that every ship choices a strategy of fight respecting if an enemy object is heavy-attack, mobile, supervisor or other ship then including data how object X should fight with object Y in object Y make the design simply unusually strange. And probably a situation in which managing such code will be impossible or very hard will appear soon.

>> For example if one is making a space-war game in which there are many
>> kinds of ships usage of RTTI seems quite logical to me.

> How can you be sure all kinds of ships are correctly handled by all of
> your code? You can't. You have to manually inspect all switches.



Yes. But note that in the fact it is a case in which you have to check it manually anyway. If data about objects of given classes are scattered in other classes then things are undoubtedly worse.

A solution here could be that each definition of class representing the ship is hold in one file (or one directory) which preferably has no other dataand information about what are a types of ships in a game is extracted by a script.

Alain Ketterlin 08-01-2012 01:57 PM

Re: Why RTTI is considered as a bad design?
 
davidkevin@o2.pl writes:

> W dniu ┼Ťroda, 1 sierpnia 2012 10:57:06 UTC+2 u┼╝ytkownik Alain Ketterlin napisa┼é:
>> davidkevin@o2.pl writes:
>> I can't parse your remark here. If you mean that an external module may
>> need dynamic type information on your objects to be able to handle them
>> properly, then why not provide the correct functions in your own
>> classes?

>
> Because such representation could be completely inconsistent with a
> problem we are trying to solve. If we assume that every ship choices a
> strategy of fight respecting if an enemy object is heavy-attack,
> mobile, supervisor or other ship then including data how object X
> should fight with object Y in object Y make the design simply
> unusually strange. And probably a situation in which managing such
> code will be impossible or very hard will appear soon.


OK, that's what Marcel mentionned in another message: you need multiple
dispatch (http://en.wikipedia.org/wiki/Multiple_dispatch).

>>> For example if one is making a space-war game in which there are many
>>> kinds of ships usage of RTTI seems quite logical to me.

>> How can you be sure all kinds of ships are correctly handled by all of
>> your code? You can't. You have to manually inspect all switches.

>
> Yes. But note that in the fact it is a case in which you have to check
> it manually anyway. If data about objects of given classes are
> scattered in other classes then things are undoubtedly worse.
>
> A solution here could be that each definition of class representing
> the ship is hold in one file (or one directory) which preferably has
> no other data and information about what are a types of ships in a
> game is extracted by a script.


If I were you, I would use an enum enumerating the classes, and abstract
away the strategy in a distinct class. At least your nested switches
would be checked for completeness.

-- Alain.

Noah Roberts 08-06-2012 06:43 PM

Re: Why RTTI is considered as a bad design?
 
On Wednesday, August 1, 2012 1:23:58 AM UTC-7, (unknown) wrote:
> Hi,
>
> what is a reason for which RTTI is considered as a bad design?
>
> Stroustrup has written in his book TC++PL that the most common case of usage RTTI technique is with switch instruction, when one want to decide whatcode should be executed basing on what is a "real" type of a passed object.. There is given an example in which an object of shape class was passed to the function and different actions were executed depending on that whether a shape is circle, square, triangle, etc. He has written that such construction is a sign that one should replace the switch-case sequence by virtual functions.


See Liskov Substitution Principle: http://en.wikipedia.org/wiki/Liskov_...tion_principle

If your code looks like so:

if (type_1 * ptr = dynamic_cast<type_1*>(somePtr))
....
else if (type_2 * ptr = dynamic_cast<type_2*>(somePtr))
....

You're violating the principle. What this means is that all places that look like this will have to be searched for, found, and modified if you add anew type behind the abstraction. This can quite rapidly explode into a maintenance nightmare and cause bugs that are difficult and/or impossible to find.

This doesn't mean that RTTI in and of itself is bad, only that this kind ofuse of it is bad. For a good use of RTTI review Alexandrescu's visitor ormultiple-dispatch system. These systems do not fall prey to the same kinds of problems because they either do not violate LSP at all (because they're a chain of responsibility that forwards the type on if the check fails) or do so in a localized abstraction that can be reused and hide the facts from all the client code that would otherwise be fragile.

Nick Keighley 08-07-2012 07:24 AM

Re: Why RTTI is considered as a bad design?
 
On Aug 6, 7:43*pm, Noah Roberts <roberts.n...@gmail.com> wrote:
> On Wednesday, August 1, 2012 1:23:58 AM UTC-7, (unknown) wrote:
> > Hi,

>
> > what is a reason for which RTTI is considered as a bad design?

>
> > Stroustrup has written in his book TC++PL that the most common case of usage RTTI technique is with switch instruction, when one want to decide what code should be executed basing on what is a "real" type of a passed object. There is *given an example in which an object of shape class was passed to the function and different actions were executed depending on that whether a shape is circle, square, triangle, etc. He has written that such construction is a sign that one should replace the switch-case sequence by virtual functions.

>
> See Liskov Substitution Principle:http://en.wikipedia.org/wiki/Liskov_...tion_principle
>
> If your code looks like so:
>
> if (type_1 * ptr = dynamic_cast<type_1*>(somePtr))
> ...
> else if (type_2 * ptr = dynamic_cast<type_2*>(somePtr))
> ...
>
> You're violating the principle.


in what way are you violating it? And yes I did read the wikipedia
article

> *What this means is that all places that look like this will have to besearched for, found, and modified if you add a new type behind the abstraction. *This can quite rapidly explode into a maintenance nightmare and cause bugs that are difficult and/or impossible to find.


yes you've kind of thrown away the whole point of polymorphism. As a
rule of thumb look with suspicion at any 'switch' (which may be
implemented as a bunch of 'if's) that appears in a C++ program.
'Factory' patterns are one honourable exception.

> This doesn't mean that RTTI in and of itself is bad, only that this kind of use of it is bad. *For a good use of RTTI review Alexandrescu's visitor or multiple-dispatch system. *These systems do not fall prey to the same kinds of problems because they either do not violate LSP at all (because they're a chain of responsibility that forwards the type on if the check fails) or do so in a localized abstraction that can be reused and hide the facts from all the client code that would otherwise be fragile.



Noah Roberts 08-20-2012 04:00 PM

Re: Why RTTI is considered as a bad design?
 
On Tuesday, August 7, 2012 12:24:09 AM UTC-7, Nick Keighley wrote:
> On Aug 6, 7:43*pm, Noah Roberts <roberts.n...@gmail.com> wrote:
>
> > On Wednesday, August 1, 2012 1:23:58 AM UTC-7, (unknown) wrote:

>
> > > Hi,

>
> >

>
> > > what is a reason for which RTTI is considered as a bad design?

>
> >

>
> > > Stroustrup has written in his book TC++PL that the most common case of usage RTTI technique is with switch instruction, when one want to decide what code should be executed basing on what is a "real" type of a passed object. There is *given an example in which an object of shape class was passed to the function and different actions were executed depending on that whether a shape is circle, square, triangle, etc. He has written that such construction is a sign that one should replace the switch-case sequence by virtual functions.

>
> >

>
> > See Liskov Substitution Principle:http://en.wikipedia.org/wiki/Liskov_...tion_principle

>
> >

>
> > If your code looks like so:

>
> >

>
> > if (type_1 * ptr = dynamic_cast<type_1*>(somePtr))

>
> > ...

>
> > else if (type_2 * ptr = dynamic_cast<type_2*>(somePtr))

>
> > ...

>
> >

>
> > You're violating the principle.

>
>
>
> in what way are you violating it? And yes I did read the wikipedia
>
> article


The LSP says that if your function F takes type A and you pass in a type B then B should behave exactly as if it where an A. If F has to perform downcasting then A is not providing the correct abstraction and B, in some way,behaves in ways incompatible with A as it relates to F.

There are some exceptions, such as when a chain of responsibility is set up, but generally speaking if your code is downcasting to various raw types and then doing stuff you're violating LSP. If you're not violating LSP you may still be violating the Open-Closed principle.

A better illustration than I provided is the Rectangle/Square problem.

>
>
>
> > *What this means is that all places that look like this will have to be searched for, found, and modified if you add a new type behind the abstraction. *This can quite rapidly explode into a maintenance nightmare and cause bugs that are difficult and/or impossible to find.

>
>
>
> yes you've kind of thrown away the whole point of polymorphism.


Exactly.

Í÷ Tiib 08-20-2012 11:11 PM

Re: Why RTTI is considered as a bad design?
 
On Monday, August 6, 2012 9:43:24 PM UTC+3, Noah Roberts wrote:
> On Wednesday, August 1, 2012 1:23:58 AM UTC-7, (unknown) wrote:
>
> > Stroustrup has written in his book TC++PL that the most common case of usage RTTI technique is with switch instruction, when one want to decide what code should be executed basing on what is a "real" type of a passed object. There is given an example in which an object of shape class was passedto the function and different actions were executed depending on that whether a shape is circle, square, triangle, etc. He has written that such construction is a sign that one should replace the switch-case sequence by virtual functions.

>
> See Liskov Substitution Principle: http://en.wikipedia.org/wiki/Liskov_...tion_principle
>
>
> If your code looks like so:
>
>
> if (type_1 * ptr = dynamic_cast<type_1*>(somePtr))
> ...
> else if (type_2 * ptr = dynamic_cast<type_2*>(somePtr))
> ...
>
> You're violating the principle. What this means is that all places that look like this will have to be searched for, found, and modified if you adda new type behind the abstraction. This can quite rapidly explode into a maintenance nightmare and cause bugs that are difficult and/or impossible to find.
>


Usually i see dynamic_cast<>() more used for cross-casting rather than down-casting. I bring an example. A specific Door passed to SomeDoer::open(Door*) may have Lockable interface or not. To have all Doors Lockable by default would deviate from sane design since most doors can not be locked. Success of unlocking may depend of availability of Keys or LockPicks or whatever for this SomeDoer so open() forwards these problems to SomeDoer::unlock(Lockable*):

bool SomeDoer::open( Door* door ) const
{
// we might need to unlock first on some cases
Lockable* lock = dynamic_cast<Lockable*>(door);
if ( lock != NULL && lock->isLocked() && !unlock( lock ) )
{
return false;
}

return door->open();
}

Can you tell how such a situation can be resolved as elegantly without RTTI(or some self-made substitution of RTTI)?

Noah Roberts 08-21-2012 10:26 PM

Re: Why RTTI is considered as a bad design?
 
On Tuesday, August 21, 2012 6:57:06 AM UTC-7, Scott Lurndal wrote:
> =?ISO-8859-1?Q?=D6=F6_Tiib?= <ootiib@hot.ee> writes:
>
>
>
> >Usually i see dynamic_cast<>() more used for cross-casting rather than down=

>
> >-casting. I bring an example. A specific Door passed to SomeDoer::open(Door=

>
> >*) may have Lockable interface or not. To have all Doors Lockable by defaul=

>
> >t would deviate from sane design since most doors can not be locked. Succes=

>
> >s of unlocking may depend of availability of Keys or LockPicks or whatever =

>
> >for this SomeDoer so open() forwards these problems to SomeDoer::unlock(Lo=

>
> >ckable*):

>
> >

>
> > bool SomeDoer::open( Door* door ) const

>
> > {

>
> > // we might need to unlock first on some cases

>
> > Lockable* lock =3D dynamic_cast<Lockable*>(door);

>
> > if ( lock !=3D NULL && lock->isLocked() && !unlock( lock ) )

>
> > {

>
> > return false;

>
> > }

>
> >

>
> > return door->open();

>
> > }

>
> >

>
> >Can you tell how such a situation can be resolved as elegantly without RTTI=

>
> > (or some self-made substitution of RTTI)?=20

>
>
>
> The ->unlock() method becomes a no-op on a non-lockable door. In other words,
>
> one may always call unlock, and if the door is lockable, it will be unlocked;
>
> if not, no-op.


I'm not a big fan of adding functions to interfaces for subclasses or for possibly implementable interfaces. I like the RTTI method better.

LSP is just a principle and there are degrees of breaking it. This seems like a fairly reasonable one, though I might consider having a "maybe_unlock" function that does the casting (it's more reusable).

There's a balance here though. Just because there's a violation of LSP doesn't mean the code is bad, it just means that it could be and in a specificway. If you suddenly needed to make some new door type that implemented adifferent interface such that this open door function no longer worked right then you're starting to run afoul of the LSP in bad ways.

An alternative to this kind of thing is a visitor. There could be a door_opener visitor that takes a lockable and a non-lockable door as parameters. In many cases this is a much better alternative to either using RTTI or noop functions in base classes that don't belong. For this simple of an issue though it could be very tempting just to violate LSP and call it good. The minus here is that IFF something changes you didn't think would (and this happens a LOT) then you're kind of screwing yourself by being lazy. But it's a balancing act.


All times are GMT. The time now is 03:28 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.