home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / cplus / 11411 < prev    next >
Encoding:
Internet Message Format  |  1992-07-23  |  13.8 KB

  1. Xref: sparky comp.lang.c++:11411 comp.std.c++:925
  2. Newsgroups: comp.lang.c++,comp.std.c++
  3. Path: sparky!uunet!munnari.oz.au!metro!extro.ucc.su.OZ.AU!maxtal
  4. From: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
  5. Subject: Re: run-time type checking (was: Re: Covariant Types in Derived Classes)
  6. Message-ID: <1992Jul23.154254.5306@ucc.su.OZ.AU>
  7. Sender: news@ucc.su.OZ.AU
  8. Nntp-Posting-Host: extro.ucc.su.oz.au
  9. Organization: MAXTAL P/L C/- University Computing Centre, Sydney
  10. References: <1992Jul21.162659.25474@ucc.su.OZ.AU> <1992Jul22.022218.1115@cadsun.corp.mot.com>
  11. Date: Thu, 23 Jul 1992 15:42:54 GMT
  12. Lines: 332
  13.  
  14. In article <1992Jul22.022218.1115@cadsun.corp.mot.com> shang@corp.mot.com writes:
  15. >In article <1992Jul21.162659.25474@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU  
  16. >(John MAX Skaller) writes:
  17. >>     In general C++ programming I do not agree that it is
  18. >> necessary to recover arbitrary type information. That is because,
  19. >> quite simply, you CANNOT use it.
  20. >>
  21. >"In general C programming I do not agree that it is necessary to use  
  22. >inheritance of structure. That is because, quite simply, you CANNOT use it"
  23.  
  24.     Sorry, I'm not sure what you mean be inheritance of structure.
  25.  
  26. > I don't like the argument. We are not talking about C++ programming. We are  
  27. >talking about the enhancement of the C++. If this argument could make any  
  28. >sense, why should we need C++?
  29.  
  30.     Well, we need C++ because it can do lots of nice things already.
  31.  
  32. >
  33. >>     I think I should clarify here: I am arguing against
  34. >> DOWNCASTING. 
  35. >> 
  36. >I am against *unsafe* downcasting too. What we are arguring about is not the  
  37. >downcasting. 
  38.  
  39.     Ah: you misunderstand! I REALLY ARGUE AGAINST DOWNCASTING.
  40.  
  41. >It is the run time type checking: whether it is necessary.
  42.  
  43.     Given the need to do downcasting, to do it safely run-time
  44. type information is required. But I am arguing it is not necessary
  45. to downcast. So the question of needing run-time type info to
  46. do it doesn't arise.
  47.  
  48. >
  49. >>     I am not against collections of objects all derived
  50. >> from a common base provided you access them via the base.
  51. >> That is the vey point of inheritance, after all.
  52. >> In this case the objects are all of the same type:
  53. >> it is homogeneous at the level it is accessed and
  54. >> heterogeneous at the actual object level, but the actual
  55. >> object level is not accessible.
  56. >>
  57. >True. I'm always in favor of doing that. We can always add member funtions and  
  58. >virtual member functions to aviod downcasting an element in a *domestic*  
  59. >heterogeneous collection or structure. 
  60.  
  61.     Ah. I like your word *domestic*. But your statement shows backwards
  62. thoughts: we do not add virtual functions to "avoid downcasting".
  63. We design our systems properly in the first place, and then the need
  64. to downcast never arises, when our thoughts wander in that 
  65. direction one can be sure we are not thinking virtuously,
  66. and perhaps the design itself is flawed.
  67.  
  68.     Inother words, in a *domestic* system, any apparent 
  69. need for downcasting should be used as an indicator of flawed design.
  70.  
  71. >But this does not mean that the run time  
  72. >type info is not necessary. In case of a foreign heterogeneous collection, we  
  73. >often need the run time type info, need to store and export the type info  
  74. >together with the object. 
  75.  
  76.     Ah, now *foreign* systems. Here, in general, we cannot
  77. store objects directly, they must be encoded somehow. That encoding
  78. is the run-time type info.
  79.  
  80.     The problem is that you don't HAVE th objects to get the run
  81. time info FROM. You have the encodings, and the object type info
  82. is in the encoding --- not the object. So of course you must
  83. extract it to create an object of the appropriate type--- and to
  84. do that implies you KNOW the run-time type BEFORE you create
  85. the object, so it follows you dont need to ask the object
  86. for its type---you already knew the type when you created it.
  87.  
  88.     The exception---the time you DO need run-time type info
  89. is when you have a *meta-domestic* system. Like a debugger,
  90. it is a system designed to manage systems, and BOTH happen
  91. to be already C++. THEN you could use RTTI. 
  92. >
  93. >>     I am not against collections of objects of completely
  94. >> unrelated types provided the types are drawn from a finite
  95. >> and statically known set. In this case there is a 'type' which
  96. >> is the finite union of those types, so again, the collection
  97. >> is really homogeneous wrt that type.
  98. >>
  99. >This case exactly examplifies the necessity of runtime type info. Given an  
  100. >element in this collection, you need run time type info to identify its type.  
  101. >Otherwise, how do you do with the element which may be in one of the types that  
  102. >are *completely unrelated*, say { int, float, doulbe }?
  103.  
  104.     You need to know the type. But you DO NOT HAVE TO ASK THE OBJECT
  105. WHAT TYPE IT IS. You have to store a code WITH the object that you
  106. access separately. 
  107.  
  108.     And notice there is NO issue of downcasting here. The issue
  109. is one of SELECTION. From a FINITE number of alternatives.
  110. From a KNOWN FINITE number of alternatives.
  111.  
  112.     In the case of downcasting from a base to a derived class
  113. you CANNOT know the alternatives, you CANNOT know what the
  114. derived types are,m because THAT LACK OF KNOWLEDGE IS 
  115. FUNDAMENTAL to the idea of inheritance. 
  116. >
  117. >> 
  118. >>     I am against using, in general programming,
  119. >> DOWNCASTING or run-time type information to defeat the type system.
  120. >>
  121. >I just don't understand! 
  122. >Run time type check is a facillity to prevent careless  
  123. >downcast to defeat the type system. 
  124. >How can you say that it is used in general  
  125. >programming to defeat the type system?
  126.  
  127.     Because if you are using it in *domestic* programs to downcast
  128. safely, you are using it to downcast, and downcasting is defeating
  129. a promise made by the concept of inheritance: that promise is
  130. called the OPEN/CLOSED principle. It is the cornerstone of
  131. object oriented design (well, actually, class-oriented design).
  132.  
  133.     It makes the promise that an algorithm applied to
  134. a class B will continue to work for ALL classes D1, D2, D3
  135. where D1, D2, etc are derived fomr B.
  136.  
  137.     The way this promise is enforced is to hide ALL
  138. details of D1, D2, D3 etc other than those shared in
  139. class B from the algorithm.
  140.  
  141.     If you downcast from the base class B you are learning
  142. something about, say, class D1 that you weren't supposed to know.
  143. If you use that knowledge, you will become unstuck.
  144.  
  145.     Let me give you an example. Suppose class D1 has a function
  146. f() while B has no such function. You have an algorithm that
  147. downcasts to D1 from B and calls f().
  148.  
  149.     But then you change D1 to NOT have a function f().
  150.  
  151.     Suddenly, the algorithm FAILS. (It won't even compile).
  152. [Too bad if the algorithm was locked away in binary form,
  153. then it will fail at link time, or if linkage is dynamic, who knows?]
  154.  
  155.     Now you see you have caused an algorithm which, by its
  156. declaration ONLY DEPENDED ON THE INTERFACE (and semantics :-)
  157. of class B to fail --- BY MODIFYING D1, which is derived from
  158. B. You have VOIDED THE OPEN/CLOSED PRINCIPLE by using a downcast.
  159.  
  160. Now again: before we can discuss when and how to use RTTI, I need
  161. you to understand that the OPEN/CLOSED principle is voided
  162. by using downcasting and to agree that this is not desirable.
  163.  
  164. I need you to see the issue IS NOT ABOUT THE SAFETY OF DOWNCASTING.
  165.  
  166. The issue is, how can one carefully discriminate the legitimate
  167. use of RTTI in *meta-domestic* systems, and maybe in
  168. *foreign* systems, from its illegitimate use for
  169. downcasting in *domestic* systems.
  170.  
  171. >>     I agree that in Debuggers and other such programs
  172. >> these facilities are essential, indeed, you need much more
  173. >> than a mere safe downcast or run-time type code. In a debugger,
  174. >> for example, you need in effect run-time access
  175. >> to the complete declaration and definintion of each class in
  176. >> the whole program!
  177. >>
  178. >A simple type id can be a key for a debugger to access to the complete  
  179. >declaration and definintion of each class in the whole program. We are not  
  180. >necessary to include the complete type information at run time.
  181.  
  182.     You do if the debugger is any good.
  183. >
  184. >>     C++ does NOT have facilities at present to do this.
  185. >> I am NOT against adding them. But I would be against using these
  186. >> facilities in the general programming context for which C++
  187. >> was intended and where such mechanism are *dangerous*.
  188. >>
  189. >Again, I can't understand. 
  190. >Run time type check is not a dangerous mechanism. 
  191.  
  192.     Run time type information is INHERENTLY DANGEROUS, 
  193. because it can provide access to information that the type
  194. system has DELIBERATELY HIDDEN. The only reason you want run-time
  195. information is that YOU DONT HAVE INFORMATION THE SYSTEM HAS
  196. HIDDEN FROM YOU DELIBERATELY, PREICSELY BECAUSE ANY ATTEMPT
  197. TO USE THAT INFORMATION IS UNSAFE TO USE.
  198.  
  199.     The fact that you can use it to convert a base class
  200. does not make that conversion safe. Just because you get back
  201. a pointer you  know is the right type DOESN'T mean
  202. you were entitled to use that pointer.
  203.  
  204. >On  
  205. >the contrary, it is used prevent potential dangers.
  206. >  
  207. >>     Clearly, for example, a debugger which allows you
  208. >> to modify instances of a class breaks encapsulation!
  209. >> It breaks almost every principle you can think of. 
  210. >> It is meant to: you use the debugger when a more important
  211. >> thing is already broken : your program :-)
  212. >> 
  213. >Here, you goes too far. A debugger can break every principle of encapsulation  
  214. >and protection only through low level programming facillities (e.g. the bitwise  
  215. >and bytewise read/write, enforced typecasting between different types, machine  
  216. >addresses, etc.). 
  217.  
  218.     You confuse 'breaking the system' with causing a fault.
  219. To cause a fault, you need only write somewhere in memory
  220. that you weren't meant to. To do that you MUST use a cast.
  221. So casts are bad. (Conversions are not, however).
  222.  
  223.     A 'hacker' breaks system security when e accesses the system.
  224. That doesn't mean the system is 'messed up', or the file system
  225. destroyed. None-the-less, the system is *broken* when security
  226. is breached *even if no damage is done*.
  227.  
  228.     In the case of downcasting the problem is the same as for
  229. any old casting: you have access to information you shouldn't have.
  230. The reason you shouldn't have it is that if you do you MIGHT
  231. proceed to destroy the system integrity, by breaching
  232. promises the system has made.
  233.  
  234.     For example, if I give you an animal pointer,
  235. and it has read only functions ONLY, I expect the object to
  236. remain unchanged.
  237.  
  238.     If you cast it to a Mammal, which has mutator functions,
  239. and proceed to mutate it, I will be very annoyed. I want the
  240. system to PROMISE ME YOU CANT DO THAT, at least not privately.
  241.  
  242. >But a debugger can never break any principle of encapsulation  
  243. >and protection only through run time type check. 
  244.  
  245.     OF COURSE IT CAN. The debugger has access to the
  246. private data of an object. The debugger is not a member function
  247. of the object. THEREFORE, unequivocably, the debugger has broken
  248. the encapsulation of the object (even if it is a benign debugger
  249. and wont abuse the priviledge).
  250.  
  251. >Remember: run time type  checking does not allow to cast objects 
  252. >which are actually of different types.
  253.  
  254.     Agreed. But it facilitates casting. Casting is bad.
  255. (Usually) Since we dont want to cast things, we dont need to
  256. do it safely!
  257.  
  258. >
  259. >Even we stick to homogeneous programming, we still need run time type checking.  
  260. >One of your reason against the concept of "thisclass" is that it needs run time  
  261. >type checking, which you view as a disadvantadge. "thisclass" is just a  
  262. >facillity to describle homogeneous data structure.
  263.  
  264.     Yes. I'm not necessarily against 'thisclass', I merely pointed out
  265. that it has some disadvantages. Requiring RTTI is a disadvantage
  266. because we dont yet have it :-)
  267. >
  268. >Okay, let's get rid of the concept of "thisclass" for the time being. Now, is  
  269. >it true that run time type checking is no longer needed for homogeneous data  
  270. >structure? No. 
  271.  
  272.     We still disagree: for domestic systems, yes, RTTI is NEVER 
  273. needed. I've never needed it. I always know what types I'm working with!
  274.  
  275. [Actually, i cheat a bit in template classes to achieve code reuse,
  276. I sometimes cast void* to T*, but is not NECESSARY, just expedient]
  277.  
  278.  
  279. >Without covariant type specification (now, we come to our  
  280. >original subject) in derived classes, we still have to run time type check the  
  281. >type of arguments in derived classes in order to prevent any violation. 
  282.  
  283.     NO, you have to accept the restriction of single dispatch.
  284.     The ONLY object you know the type of is the *this object.
  285.     (And any others passed by value).
  286.  
  287. >Let's  
  288. >consider a homogeneous animal collection:
  289. >
  290. >    class Animal;
  291. >    class AnimalGroup
  292. >    { protected:
  293. >       Animal * animals;
  294. >      public:
  295. >       virtual void accept (Animal *ap) {...};
  296. >        ...
  297. >    };
  298. >
  299. >Since it is a homogeneous collection, it should contains animals of the same  
  300. >type. The concept of "same type" is relatively dependend on what the class  
  301. >designer means. 
  302.     
  303.     No, quite wrong. Same type means 'common properties
  304. of all animals'. It SPECIFICALLY excludes you knowing about
  305. whether the animal has webbed feet. Because snakes dont have
  306. feet, so its not a property common to all animals.
  307.  
  308. >Suppose the same type" is based on the *family* according to  
  309. >the systemtic zoology. Then the collection should be of all dogs, or all cats,  
  310. >etc. 
  311.  
  312. Then you should have a collection of all dogs, or all cats,
  313. not all animals.
  314. This is why some people like templates a lot.
  315.  
  316.  
  317. Now you have further example of a serious problem, but I will
  318. simplify it.
  319.  
  320. The problem is why you proposed 'thisclass' and is a real problem.
  321. It is a problem for which RTTI is the wrong solution,
  322. but never-the-less is the best we will get for a while.
  323. We really need multiple dispatch.
  324.  
  325.  
  326. class Animal {
  327.     int mate(Animal&);
  328. };
  329. class Dog : Animal {
  330.     int mate (Animal&);
  331. };
  332.  
  333. We REALLY want Dog::mate(Dog&), but we cant have it.
  334.  
  335. This is a flaw in Object Oriented Programming IMHO.
  336. The solution requires multimethods which are inherently
  337. functional.
  338.  
  339.  
  340. -- 
  341. ;----------------------------------------------------------------------
  342.         JOHN (MAX) SKALLER,         maxtal@extro.ucc.su.oz.au
  343.     Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
  344. ;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
  345.