home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / lang / ada / 2374 < prev    next >
Encoding:
Text File  |  1992-08-17  |  5.6 KB  |  150 lines

  1. Newsgroups: comp.lang.ada
  2. Path: sparky!uunet!noc.near.net!inmet!cobra!bwhite
  3. From: bwhite@cobra.camb.inmet.com (Bill White)
  4. Subject: Re: Ada 9x Dispatching Question
  5. Message-ID: <1992Aug17.215219.967@inmet.camb.inmet.com>
  6. Keywords: Ada Dispatching Polymorphism
  7. Sender: news@inmet.camb.inmet.com
  8. Nntp-Posting-Host: cobra
  9. Organization: Intermetrics Inc, Cambridge MA
  10. References: <334@sps.com>
  11. Date: Mon, 17 Aug 1992 21:52:19 GMT
  12. Lines: 136
  13.  
  14. In response to Joe Tallet's recent note in comp.lang.ada:
  15.  
  16. Dispatching only occurs when (1) the operation is an operation of a tagged
  17. type, and (2) the operand is of a class-wide type.  It does not matter that
  18. the operation is obtained by an expanded name or by direct (use) visibility.
  19. Given this, the Shapes package looks like:
  20.  
  21. package Shapes is
  22.     type shape is tagged ... ;
  23.     procedure draw (x : shape) is <>; -- abstract
  24. end Shapes;
  25.  
  26. This is Alex Blakemore's original definition.  (Is this name right?)
  27.  
  28. Now, draw is an abstract operation of the type shape.  However,
  29. since it is abstract, it must be redefined for each child type of
  30. shape.  An example is:
  31.  
  32. with Shapes;
  33. package Circles is
  34.   type circle is new Shapes.shape ...;  
  35.    -- inherits primitive ops of shape
  36.   procedure draw (x : circle); 
  37.    -- overide draw, now circle is not abstract
  38. end Circle;
  39. This is also Alex Blakemore's definition I believe.  After this
  40. definition, draw is a primitive operation of circle.
  41.  
  42. In order to get dispatching, we need to have an operand which is of
  43. a class-wide type.  Alex's later example shows this.
  44.  
  45. with Shapes;
  46. procedure process(x : Shapes.shape'class; y : Shapes.shape);
  47. begin
  48.     ...
  49.     Shapes.draw(x); -- <-- This is a dispatching call
  50.     Shapes.draw(y); -- <-- This is not a dispatching call, since
  51.             --     the type of y is not class-wide.
  52.             --     In fact, since Shapes.draw is abstract,
  53.             --     this call is not allowed.
  54.     ...
  55. end process;
  56.  
  57. The reason I have gone on at such length is that there is another wrinkle
  58. here.  Inside of the body of the circular draw, the compiler assumes that 
  59. the parameter x is actually a circle.  This is true even if the operation
  60. was called through dispatching.  For example, imagine that we have:
  61.  
  62.     with Shapes; use Shapes;
  63.     with Circles; use Circles;
  64.     package ProcessGeometry is
  65.     end Process Geometry;
  66.     package body ProcessGeometry is
  67.         circ_object : circle;
  68.         ...
  69.     begin
  70.         draw(Shapes.shape'class(circ_object)); -- dispatching
  71.         draw(circ_object);            -- not dispatching
  72.     end ProcessGeometry;
  73.  
  74. These two calls are to the same procedure, but the first is dispatching
  75. and the second is not.  Inside of the body of circle's draw operation,
  76. the object x is assumed to be a circle -- this is even if it is in a class
  77. derived from circle.
  78.  
  79. We need a better example.  This one is somewhat contrived, and is probably
  80. more long-winded than necessary, but it illustrates the main point.  
  81. Imagine first that I have a Geometry manager package which has an operation 
  82. to draw arbitrary circular arcs.  This operation is given by:
  83.     package GeometryManager is
  84.         type Point is ...;
  85.         type Distance is ...;
  86.         type Angle is ...;
  87.         DrawArc(Center : Point; Radius : Distance;
  88.             StartAngle : Angle; EndAngle: Angle);
  89.     end GeometryManager;
  90.  
  91.  
  92. Imagine furthermore that I have several possible ways of representing circles. 
  93. One is as a center and a radius.  Another is as three points which lie 
  94. on the circle.  There may be more.  These representations will be child 
  95. types of circle.
  96.  
  97. Now, we flesh out the implementation of circles somewhat.  The draw
  98. routine of a circle will acquire the center and radius of the
  99. circle and then call the GeometryManager's routine to draw a circular
  100. arc.  The two representations of circles have different ways of
  101. getting the center and radius.  In one they are there to look up,
  102. and in the other they must be calculated using a standard formula.
  103. In any case, the operations "calculate the center" and "calculate
  104. the radius" are different operations for the different child types
  105. of circle.  We make them dispatching operations.
  106. with Shapes;
  107. with GeometryManager;
  108. package Circles is
  109.     type circle is new Shapes.shape ...;
  110.     procedure draw(x : circle);
  111.     function center(x : circle) return GeometryManager.Point is <>;
  112.     function radius(x : circle) return GeometryManager.Distance is <>;
  113. end Circles;
  114.  
  115. package body Circles is
  116.     procedure draw(x : circle) is
  117.     begin
  118.     --
  119.     -- If we do some calculation using the center of x,
  120.     -- we will get the non-dispatching operation here.
  121.     -- For example, since the circular center is abstract,
  122.     --         ..., center(x), ...
  123.     -- would not be allowed.
  124.     --
  125.     GeometryManager.DrawArc(center(circle'class(x)),
  126.                --          ^  Notice the conversion
  127.                 radius(circle'class(x)),
  128.                --          ^  Notice the conversion
  129.                 Angle(0), Angle(360));
  130.     end draw;
  131. end Circles;
  132.  
  133. We want the operations center and radius to be dispatching. We must 
  134. convert the parameter x to be of class wide type inside of the body of
  135. draw.  Even though the compiler things that the type of x is circle, 
  136. the run-time type of x is some child type of circle.  This is the
  137. only way to get re-dispatching behavior.
  138.  
  139. The MRT has discussed this at length in the past.  Tucker believes that
  140. it is important to have a syntactic marker to tell when a call is
  141. dispatching.  An alternative rule would be the C++ rule, where all
  142. dispatching operations dispatch always.  (Ada9X dispatching operations
  143. are roughly equivalent to C++ virtual operations.)  This means that the 
  144. compiler could not replace a dispatching call with a non-dispatching
  145. call even if the compiler knows where the routine is going to go
  146. anyway.  This is considered expensive.
  147.  
  148.                     Peace,
  149.                     Bill White
  150.