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-12 02:10:46 PST Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!news-spur1.maxwell.syr.edu!news.maxwell.syr.edu!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!fu-berlin.de!uni-berlin.de!tar-alcarin.cbb-automation.DE!not-for-mail From: dmitry@elros.cbb-automation.de (Dmitry A. Kazakov) Newsgroups: comp.lang.ada,comp.object Subject: Re: Merits of re-dispatching [LONG] Date: Tue, 12 Feb 2002 10:13:03 GMT Message-ID: <3c68da53.91694562@News.CIS.DFN.DE> References: <3c62524f.93369796@News.CIS.DFN.DE> <3c63eb54.407824716@news.cis.dfn.de> NNTP-Posting-Host: tar-alcarin.cbb-automation.de (212.79.194.111) X-Trace: fu-berlin.de 1013508640 47408204 212.79.194.111 (16 [77047]) X-Newsreader: Forte Free Agent 1.21/32.243 Xref: archiver1.google.com comp.lang.ada:19910 comp.object:34179 Date: 2002-02-12T10:13:03+00:00 List-Id: On Fri, 08 Feb 2002 18:33:31 GMT, nickroberts@ukf.net (Nick Roberts) wrote: >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! I see no pressing necessity in supporting re-dispatching. At the same time the price of its supporting is high. >> 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. This is the C++'s way. I would prefer a more radical aproach, i.e. removing the language support of re-dispatching. It means that the language will not require that the conversion class->specific is a view conversion. Just remove this requirement and re-dispatching will disappear. >>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). But you still can do it explicitly by providing a type identification member. Then generally, I have a strong feeling [not a proof of course] that all that genuine cases are in fact more or less design flaws. >>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! 1. It would simplify the language. More regularity is IMO better. And yes, I would like to have class-wide task and protected object types (:-)) 2. Extensible enumeration types are good candidates for class-wide programming. 3. Let I want some special overflow processing for a numeric type? I just derive from it and then override +. I can do it even in Ada 83, but I cannot write a class-wide routine which will work with both types. So I must call the devil = generics. (:-)) 2 .& 3. Consider class-wide routines as an alternative to generics. In many cases I would definitely prefer Integer'Class to type Int range <>; 4. Attributes like Integer'Image (x) should be overridable dispatching primitive routines: Image (x : Integer). 5. Interface inheritance. Forget for a minute that in Ada implementation is always inherited. Consider you are developing a type MyString. String is an array in the sense that it *looks* like an array. In other words it has the interface of an array. So you derive your type from an array type, provide a private implementation [which possibly would be a record type], but the interface is of an array. So you have indexing, slices etc. >>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. Well, I was always for MI and MD! (:-)) >>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). I would make "redraw" class-wide and represent all child windows by class-wide pointers. Another example, where re-dispatching appears is layered protocols. You have dispatching abstract Get to read one byte, then in some derived type you have dispatching Get to read the mantra flux distribution. You must somehow dispatch from there to read your bytes. Oops, that would be re-dispatching! However, in this case one could decouple the low-level I/O primitives in some separate type Driver and use it as an access discriminant. >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. Of course this is a question of balance. It is not that re-dispatching should be disallowed. There is no way to do it as long a class-wide self-pointer can be put into the object. My point is that there is no need to support re-dispatching at the language level [the requirement that the conversion to A'Class when applied to the formal parameter gives you the actual type) Regards, Dmitry Kazakov