From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,7a180be12347b9d3 X-Google-Attributes: gid103376,public X-Google-Thread: 1108a1,7a180be12347b9d3 X-Google-Attributes: gid1108a1,public X-Google-ArrivalTime: 2002-02-08 10:30:54 PST Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!logbridge.uoregon.edu!fu-berlin.de!uni-berlin.de!ppp-1-56.5800-14.telinco.NET!not-for-mail From: nickroberts@ukf.net (Nick Roberts) Newsgroups: comp.lang.ada,comp.object Subject: Re: Merits of re-dispatching [LONG] Date: Fri, 08 Feb 2002 18:33:31 GMT Message-ID: <3c63eb54.407824716@news.cis.dfn.de> References: <3c62524f.93369796@News.CIS.DFN.DE> NNTP-Posting-Host: ppp-1-56.5800-14.telinco.net (212.1.148.56) X-Trace: fu-berlin.de 1013193051 45832250 212.1.148.56 (16 [25716]) X-Newsreader: Forte Free Agent 1.21/32.243 Xref: archiver1.google.com comp.lang.ada:19790 comp.object:33699 Date: 2002-02-08T18:33:31+00:00 List-Id: On Thu, 07 Feb 2002 10:26:00 GMT, dmitry@elros.cbb-automation.de (Dmitry A. Kazakov) wrote: >C++ and Ada 95 support re-dispatching, which I think is inherently >unsafe. Consider the following: >... >procedure Finalize (Object : in out A) is >begin > Foo (A'Class (Object)); -- Re-dispatch to the child's Foo >end Finalize; This is what I would certainly describe as a 'pathalogical' case. It is a basic principle in Finalize (it should be bloody obvious, but all the same it should be taught) that you normally assume any and all extensions to the Object have already been finalised, and so you don't try something like the above redispatching! >Though merits of re-dispatching seem to me suspicious, I'd like you to expand on that statement, please! > it is easy to >implement it without casting. >... >With re-dispatching the contract of Finalize is not clear. According >to its specification it receives an argument of type A. Thus there >should be no legal way for Finalize to discover that actually an >instance of AA was passed. I.e. Foo (A'Class (Object)) should always >statically dispatch to A.Foo. Yet it dispatches to AA.Foo. This is a >violation of substitutability. [Not that I hold LSP for a sacral cow, >but there is no reason to encourage its violation.] If the implementor is going to do the above, it is his responsibility to ensure it will work; otherwise he must not do it (that is the 'contract' implicit in implementing Finalization). I would say a compiler should give a strong warning about redispatching on Object in Finalization; maybe it should be explicitly made illegal in the next language revision. >I think that there >should be no exceptions from the rule "Want dispatching in a >subprogram? Make the argument class wide." A nice idea, but it would be too restrictive. There are many genuine cases where it is necessary to be able to dispatch on an object passed in as a specific type (to a primitive operation of that type). >What is worse is that implementation of re-dispatching requires that >the type tag be accessible for not only class wide objects but also >for specific ones. Thus tagged types are reference types, type tag >shall be a part of a tagged object. As a consequence elementary types >cannot be tagged and so they are excluded from OOP. Maybe I have >missed something, but I see no other reason why not to allow for all >types inheritance, dispatching subroutines and class wide objects. Except that it is really very unlikely in practice to be particularly useful. How many times, in real software, is a primary type not going to have to be a record type anyway? Very few! >Methodically re-dispatching breaks segregation of class wide and >specific types returning us to the languages like C++, where there is >no difference between them. So Ada lingers somewhere in-between. To be honest, I think Ada lingers somewhere inbetween the equally onerous extremes of the pig trough and the ivory tower. The fact that Ada is pragmatic enough to permit a primitive operation with two or more parameters of the same (tagged) type, and a primitive operation of a tagged type with futher parameters of that type's class, is as commendable as the fact that it eschews features, such as multiple inheritance, which may be very sexy, but have serious practical difficulties. >Is there examples where re-dispatching is really unavoidable? Consider a tagged type (class) that represents a 'window' in a GUI subsystem. It is derived from a 'drawable' type (class), that has a (virtual) primitive operation 'redraw', which is called (by the window manager/executive) in order to make the object redraw itself, whenever necessary. Our 'window' type (class) is a kind of container: it can contain a number of other drawables. Perhaps it also has a background image that it draws behind its components. Now consider its implementation of 'redraw'. This must surely be on the lines of: (a) draw the background image; (b) for each component drawable, call its 'redraw' (with appropriate parameters). In Ada, the calls to the 'redraw' of each component will be explicitly dispatching calls. (In C++, they will be dispatched to implicitly.) The point to understand is that one of those components could be of the 'window' type (representing a window-within-a-window presumably); thus the primitive redraw operation of the window type ends up redispatching to the redraw of another window object. And yes, this situation does threaten the danger of an infinite loop (many programming situations do). I think, Dmitry, you will find in practice many genuine cases where this kind of redispatching is impractical to avoid. All the best, -- Nick Roberts