comp.lang.ada
 help / color / mirror / Atom feed
* Merits of re-dispatching [LONG]
@ 2002-02-07 10:26 Dmitry A. Kazakov
  2002-02-07 15:03 ` Hyman Rosen
                   ` (4 more replies)
  0 siblings, 5 replies; 36+ messages in thread
From: Dmitry A. Kazakov @ 2002-02-07 10:26 UTC (permalink / raw)


Hi!

C++ and Ada 95 support re-dispatching, which I think is inherently
unsafe. Consider the following:

type A is new Ada.Finalization.Limited_Controlled with ...
procedure Foo  (Object : A);
procedure Finalize (Object : in out A) ;

Now let AA derived from A override Foo and Finalize:

type AA is new A with record
   ... -- Some components, which may use components of A
end record;
procedure Foo  (Object : AA) ;
procedure Finalize (Object : in out AA) is
begin
   ... -- Finalize components, maybe accessing components of A
   Finalize (A (Object)); -- Finalize parent
end Finalize;

Consider the following implementation of A.Finalize:

procedure Finalize (Object : in out A) is
begin
   Foo (A'Class (Object)); -- Re-dispatch to the child's Foo
end Finalize;

When A is finalized as a part of AA, it re-dispatches to AA.Foo, which
may access already finalized parts of AA! A user of A has no way to
learn the problem from the specification of A. He must look into the
implementation of A.Finalize. The same is valid for Initialize as
well. Actually it is a common error among fresh baked C++ programmers
to call virtual functions (dispatch) from constructors.

Though merits of re-dispatching seem to me suspicious, it is easy to
implement it without casting. Let we really want object's IDENTITY,
i.e. objects which always "know" their actual type. Ada 95 perfectly
supports this without any casting!

package Self_Identifying is
   type A is new
      Ada.Finalization.Limited_Controlled with private;
   type A_Ptr is access all A'Class;
   procedure Finalize (Object : in out A);
   procedure Foo (Object : in out A);
private
   type A is new
      Ada.Finalization.Limited_Controlled with
   record
      Self : A_Ptr := A'Unchecked_Access; -- Class wide self-reference
   end record;
end Self_Identifying;

The implementation of Finalize:

   procedure Finalize (Object : in out A) is
   begin
      Foo (Object.Self.all); -- Dispatch to child's Foo
   end Finalize;

Now, if

   type AA is new A with null record;
   procedure Foo (Object : in out AA);

Then an object of AA will dispatch to AA.Foo during finalization
exactly like in the first example. The difference is that
self-identification can be explicitly exposed and documented:

   function Identity (Object : A['Class]) return A_Ptr is
   begin
      return Object.Self;
   end Identity;

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.] I think that there
should be no exceptions from the rule "Want dispatching in a
subprogram? Make the argument class wide."

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.

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.

Is there examples where re-dispatching is really unavoidable? 

Regards,
Dmitry Kazakov



^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2002-02-25  8:51 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-02-07 10:26 Merits of re-dispatching [LONG] Dmitry A. Kazakov
2002-02-07 15:03 ` Hyman Rosen
2002-02-08  1:29   ` Matthew Heaney
2002-02-08  9:16     ` Dmitry A. Kazakov
2002-02-08 18:30       ` Hyman Rosen
2002-02-09  0:10         ` Matthew Heaney
2002-02-12  8:32         ` Dmitry A. Kazakov
2002-02-12 21:37           ` Hyman Rosen
2002-02-13  9:29             ` Dmitry A. Kazakov
2002-02-13 14:32               ` Hyman Rosen
2002-02-13 19:58           ` Dave Harris
2002-02-14 15:06             ` Dmitry A. Kazakov
2002-02-16 12:10               ` Dave Harris
2002-02-18  8:57                 ` Dmitry A. Kazakov
2002-02-18 19:47                   ` Merits of re-dispatching Dave Harris
2002-02-19  9:20                     ` Dmitry A. Kazakov
2002-02-21  5:49                       ` Hyman Rosen
2002-02-21  9:04                         ` Dmitry A. Kazakov
2002-02-21 18:17                           ` Hyman Rosen
2002-02-22  9:21                             ` Dmitry A. Kazakov
2002-02-22 16:59                               ` Hyman Rosen
2002-02-25  8:51                                 ` Dmitry A. Kazakov
2002-02-08 23:51       ` Merits of re-dispatching [LONG] Matthew Heaney
2002-02-12  9:02         ` Dmitry A. Kazakov
2002-02-07 23:40 ` Nick Roberts
2002-02-08  8:56   ` Dmitry A. Kazakov
2002-02-08  1:06 ` Matthew Heaney
2002-02-08  9:48   ` Dmitry A. Kazakov
2002-02-09  0:16     ` Matthew Heaney
2002-02-08 18:10   ` Hyman Rosen
2002-02-09  0:41     ` Matthew Heaney
2002-02-08 18:33 ` Nick Roberts
2002-02-09  4:07   ` Nick Roberts
2002-02-12 10:13   ` Dmitry A. Kazakov
2002-02-14 20:57 ` Tucker Taft
2002-02-15 15:43   ` Dmitry A. Kazakov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox