comp.lang.ada
 help / color / mirror / Atom feed
* Re: How to write TYPECASE in Ada 95?
  1999-02-05  0:00 ` Brian Rogoff
@ 1999-02-05  0:00   ` David C. Hoos, Sr.
  1999-02-05  0:00     ` Brian Rogoff
  1999-02-06  0:00   ` Ed Falis
  1 sibling, 1 reply; 34+ messages in thread
From: David C. Hoos, Sr. @ 1999-02-05  0:00 UTC (permalink / raw)



Brian Rogoff wrote in message ...
>On 5 Feb 1999, Norman Ramsey wrote:
<large snip>
>There is no typecase, but if you want exact tag comparisons you can
>use
>
> if p'Tag = Painted_Point then
> ... do someting with Painted_Point
> elsif p'Tag = Tall_Point then
> ... yadda yadda yadda
> ...
Don't you mean:

if P'Tag = Painted_Point'Tag then
... do someting with Painted_Point
elsif P'Tag = Tall_Point'Tag then
... yadda yadda yadda
...
??








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

* Re: How to write TYPECASE in Ada 95?
  1999-02-05  0:00   ` David C. Hoos, Sr.
@ 1999-02-05  0:00     ` Brian Rogoff
  0 siblings, 0 replies; 34+ messages in thread
From: Brian Rogoff @ 1999-02-05  0:00 UTC (permalink / raw)


On Fri, 5 Feb 1999, David C. Hoos, Sr. wrote:
> Brian Rogoff wrote in message ...
> >On 5 Feb 1999, Norman Ramsey wrote:
> <large snip>
> >There is no typecase, but if you want exact tag comparisons you can
> >use
> >
> > if p'Tag = Painted_Point then
> > ... do someting with Painted_Point
> > elsif p'Tag = Tall_Point then
> > ... yadda yadda yadda
> > ...
> Don't you mean:
> 
> if P'Tag = Painted_Point'Tag then
> ... do someting with Painted_Point
> elsif P'Tag = Tall_Point'Tag then
> ... yadda yadda yadda
> ...
> ??

Doh! Yes, of course you are correct. Thanks for pointing this out.

-- Brian





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

* How to write TYPECASE in Ada 95?
@ 1999-02-05  0:00 Norman Ramsey
  1999-02-05  0:00 ` Brian Rogoff
                   ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Norman Ramsey @ 1999-02-05  0:00 UTC (permalink / raw)



I'm trying to figure out from the reference manual how to identify
which type extension of a type I have.  For example, if I have

   type Point is tagged
         record
           X, Y : Real := 0.0;
         end record;

   type Painted_Point is new Point with
         record
           Paint : Color := White;
         end record;


   type Tall_Point is new Point with
         record
           Height : Real := 0.0;
         end record;

I'd like to be able to discriminate at run time:

   p : Point;

     ...

   if p in Painted_Point then
      ... do something with Painted_Point'(p)
   else if p in Tall_Point then
      ... do something with Tall_Point'(p)

Even better would be something like Modula-3 TYPECASE:

  (* modula-3 *)
  TYPECASE p OF
  Painted_Point (painted) => ... do something with painted
  Tall_Point    (tail)    => ... do something with tall
    ...
  END

What's the idiomatic way to express this in Ada?


Norman

-- 
Norman Ramsey
http://www.cs.virginia.edu/~nr




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

* Re: How to write TYPECASE in Ada 95?
  1999-02-05  0:00 How to write TYPECASE in Ada 95? Norman Ramsey
@ 1999-02-05  0:00 ` Brian Rogoff
  1999-02-05  0:00   ` David C. Hoos, Sr.
  1999-02-06  0:00   ` Ed Falis
  1999-02-06  0:00 ` How to write TYPECASE in Ada 95? David C. Hoos, Sr.
  1999-02-06  0:00 ` Matthew Heaney
  2 siblings, 2 replies; 34+ messages in thread
From: Brian Rogoff @ 1999-02-05  0:00 UTC (permalink / raw)


On 5 Feb 1999, Norman Ramsey wrote:
> 
> I'm trying to figure out from the reference manual how to identify
> which type extension of a type I have.  For example, if I have
> 
>    type Point is tagged
>          record
>            X, Y : Real := 0.0;
>          end record;
> 
>    type Painted_Point is new Point with
>          record
>            Paint : Color := White;
>          end record;
> 
> 
>    type Tall_Point is new Point with
>          record
>            Height : Real := 0.0;
>          end record;
> 
> I'd like to be able to discriminate at run time:
> 
>    p : Point;
> 
>      ...
> 
>    if p in Painted_Point then
>       ... do something with Painted_Point'(p)
>    else if p in Tall_Point then
>       ... do something with Tall_Point'(p)
> 
> Even better would be something like Modula-3 TYPECASE:
> 
>   (* modula-3 *)
>   TYPECASE p OF
>   Painted_Point (painted) => ... do something with painted
>   Tall_Point    (tail)    => ... do something with tall
>     ...
>   END
> 
> What's the idiomatic way to express this in Ada?

There is no typecase, but if you want exact tag comparisons you can 
use 

	if p'Tag = Painted_Point then
		... do someting with Painted_Point 
	elsif p'Tag = Tall_Point then
		... yadda yadda yadda 
	...

-- Brian





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

* Re: How to write TYPECASE in Ada 95?
  1999-02-05  0:00 ` Brian Rogoff
  1999-02-05  0:00   ` David C. Hoos, Sr.
@ 1999-02-06  0:00   ` Ed Falis
  1999-02-06  0:00     ` Nick Roberts
                       ` (2 more replies)
  1 sibling, 3 replies; 34+ messages in thread
From: Ed Falis @ 1999-02-06  0:00 UTC (permalink / raw)



> On 5 Feb 1999, Norman Ramsey wrote:
> > 
> > I'm trying to figure out from the reference manual how to identify
> > which type extension of a type I have.  For example, if I have
> > 
>
> > I'd like to be able to discriminate at run time:
> > 
> >    p : Point;
> > 
> >      ...
> > 
> >    if p in Painted_Point then
> >       ... do something with Painted_Point'(p)
> >    else if p in Tall_Point then
> >       ... do something with Tall_Point'(p)
> > 
> > Even better would be something like Modula-3 TYPECASE:
> > 
> >   (* modula-3 *)
> >   TYPECASE p OF
> >   Painted_Point (painted) => ... do something with painted
> >   Tall_Point    (tail)    => ... do something with tall
> >     ...
> >   END
> > 
> > What's the idiomatic way to express this in Ada?

I thought a good part of the point of tagged types (and support for polymorphism in other OOP's) was exactly to avoid this kind of code.

- Ed




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

* Re: How to write TYPECASE in Ada 95?
  1999-02-05  0:00 How to write TYPECASE in Ada 95? Norman Ramsey
  1999-02-05  0:00 ` Brian Rogoff
  1999-02-06  0:00 ` How to write TYPECASE in Ada 95? David C. Hoos, Sr.
@ 1999-02-06  0:00 ` Matthew Heaney
  2 siblings, 0 replies; 34+ messages in thread
From: Matthew Heaney @ 1999-02-06  0:00 UTC (permalink / raw)


nr@labrador.cs.virginia.edu (Norman Ramsey) writes:

> I'm trying to figure out from the reference manual how to identify
> which type extension of a type I have.  For example, if I have
> 
>    type Point is tagged
>          record
>            X, Y : Real := 0.0;
>          end record;
> 
>    type Painted_Point is new Point with
>          record
>            Paint : Color := White;
>          end record;
> 
> 
>    type Tall_Point is new Point with
>          record
>            Height : Real := 0.0;
>          end record;
> 
> I'd like to be able to discriminate at run time:
> 
>    p : Point;
> 
>      ...
> 
>    if p in Painted_Point then
>       ... do something with Painted_Point'(p)
>    else if p in Tall_Point then
>       ... do something with Tall_Point'(p)

You've got it right: use a membership test.  The only problem here is
that you should have said "elsif" instead of "else if".

 
> Even better would be something like Modula-3 TYPECASE:
> 
>   (* modula-3 *)
>   TYPECASE p OF
>   Painted_Point (painted) => ... do something with painted
>   Tall_Point    (tail)    => ... do something with tall
>     ...
>   END

No, you can't use case statement for this sort of thing.
 
> What's the idiomatic way to express this in Ada?

The idiomatic way in Ada --and in any object-oriented language-- is to
not do this at all.  You should be call a primitive operation of the
type that automatically dispatches according to the (type) tag of the
object.

If you insist on doing an explicit test, then use a membership test.







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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00   ` Ed Falis
@ 1999-02-06  0:00     ` Nick Roberts
  1999-02-06  0:00       ` Nick Roberts
  1999-02-17  0:00     ` Tom Moran
  1999-02-19  0:00     ` Tom Moran
  2 siblings, 1 reply; 34+ messages in thread
From: Nick Roberts @ 1999-02-06  0:00 UTC (permalink / raw)


Given

   type Root_Type is abstract tagged ...;

and

   type Variation_1 is new Root_Type with ...;
   type Variation_2 is new Root_Type with ...;

and you have a particular 'something' you might want to do to an object
which could be either of type Variation_1 or Variation_2, you might find it
clearest to create an abstract procedure

   procedure Something (X: Root_Type; ...) is abstract;

and then override this procedure with

   procedure Something (X: Variation_1; ...) ...

whose body does what is appropriate for objects of type Variation_1, and
then

   procedure Something (X: Variation_2; ...) ...

whose body does what is appropriate for objects of type Variation_2. A call
such as

   Something(A,...);

will then automatically call the correct version of Something, based on the
type of object A. This is called 'dispatching'.

Dispatching generally obviates any need for a TYPECASE construct. However,
it is sometimes the case that all those separate procedures would be
overkill. Given

   type Subvariation_1_1 is new Variation_1 with ...;
   type Subvariation_1_2 is new Variation_1 with ...;

you may have a piece of code which operates on objects of type Variation_1,
but has an extra operation, somewhere in the middle, necessary for objects
of type Subvariation_1_2 (say). In these cases, it is more sensible to use
the 'in' operator to factor out this snippet of code, e.g.

   ...
   if X in Subvariation_1_2'Class then
      ...
   end if;
   ...

You should (almost) always test for membership of a class. E.g. test "X in
Subvariation_1_2'Class" rather than "X in Subvariation_1_2", so that further
descendants of Subvariation_1_2 (if you should add any at a later date) will
still be catered for.

Use the 'in' operator, not 'Tag. The need to use 'Tag is very rare (and
always to do with I/O or interfacing).

-------------------------------------------
Nick Roberts
-------------------------------------------







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

* Re: How to write TYPECASE in Ada 95?
  1999-02-05  0:00 How to write TYPECASE in Ada 95? Norman Ramsey
  1999-02-05  0:00 ` Brian Rogoff
@ 1999-02-06  0:00 ` David C. Hoos, Sr.
  1999-02-06  0:00   ` Matthew Heaney
  1999-02-06  0:00 ` Matthew Heaney
  2 siblings, 1 reply; 34+ messages in thread
From: David C. Hoos, Sr. @ 1999-02-06  0:00 UTC (permalink / raw)


Norman Ramsey wrote in message <79fct8$9k3$1@murdoch.acc.Virginia.EDU>...
>
>I'm trying to figure out from the reference manual how to identify
>which type extension of a type I have.  For example, if I have
>
>   type Point is tagged
>         record
>           X, Y : Real := 0.0;
>         end record;
>
>   type Painted_Point is new Point with
>         record
>           Paint : Color := White;
>         end record;
>
>
>   type Tall_Point is new Point with
>         record
>           Height : Real := 0.0;
>         end record;
>
>I'd like to be able to discriminate at run time:
>
>   p : Point;
>
>     ...
>
>   if p in Painted_Point then
>      ... do something with Painted_Point'(p)
>   else if p in Tall_Point then
>      ... do something with Tall_Point'(p)
>
>Even better would be something like Modula-3 TYPECASE:
>
>  (* modula-3 *)
>  TYPECASE p OF
>  Painted_Point (painted) => ... do something with painted
>  Tall_Point    (tail)    => ... do something with tall
>    ...
>  END
>
>What's the idiomatic way to express this in Ada?
>
None of the responses to this posting (including mine) addressed the larger
question -- i.e., "What's the idiomatic way to express this in Ada?"  Ed
Falis' comment made me realize that, so here's an attempt  to answer it.

First, I would say that it would be presumptuous of me to say something was
_the_ idiomatic way to express something in Ada, because with so many of
Ada's capabilities there are multiple idioms possible, but not always any
one best way to do it.

So here is _an_idiomatic way to express this in Ada:
This is a complete working program, that I hope is helpful.

David C. Hoos, Sr.

--------- begin source code ------
package Points is

   subtype Real is Float;

   type Color is (Black, Red, Brown, Green, Yellow, Blue, Purple, White);

   type Point is tagged
      record
         X, Y : Real := 0.0;
      end record;

   -------------------------------------------------------------------------
----
   -- Show_Type (P: Point'Class);
   -- Purpose:
   --   This class-wide procedure illustrates a procedure which serves for
all
   --   types derived from its base type, regardless of future extensions
   --   unknown or even unanticipated at the time this procedure was
written.
   -------------------------------------------------------------------------
----
   procedure Show_Type (P : Point'Class);

   -------------------------------------------------------------------------
----
   -- Show_Properties (P: Point);
   -- Purpose:
   --   This procedure illustrates a procedure which serves for only the
   --   type of its parameter.  It may be called explicitly with an object
   --   of its type, or implicitly by means of a dispatching call with a
   --   class-wide object, in which case the procedure to be called is
   --   determined at run-time by the actual type of the parameter object.
   --   NOTE:  If other types are derived from Point, a Show_Properties
   --   procedure MUST be provided for that type.  This restriction is
   --   enforced at compile time.
   -------------------------------------------------------------------------
----
   procedure Show_Properties (P : Point);

   type Painted_Point is new Point with
      record
         Paint : Color := White;
      end record;

   -------------------------------------------------------------------------
----
   -- Show_Properties (P: Painted_Point);
   -- Purpose:
   --   See discussion for Show_Properties (P: Point);
   -------------------------------------------------------------------------
----
   procedure Show_Properties (P: Painted_Point);

   type Tall_Point is new Point with
      record
         Height : Real := 0.0;
      end record;

   -------------------------------------------------------------------------
----
   -- Show_Properties (P: Tall_Point);
   -- Purpose:
   --   See discussion for Show_Properties (P: Point);
   -------------------------------------------------------------------------
----
   procedure Show_Properties (P: Tall_Point);

end Points;

with Ada.Tags;
with Ada.Text_Io;
package body Points is

   procedure Show_Properties (P : Point) is
   begin
      Ada.Text_Io.Put_Line
        ("X =>" & Real'Image (P.X) &
         "Y =>" & Real'Image (P.Y));
   end Show_Properties;

   procedure Show_Properties (P: Painted_Point) is
   begin
      Show_Properties (Point (P));
      Ada.Text_Io.Put_Line
        ("Paint =>" & Color'Image (P.paint));
   end Show_Properties;

   procedure Show_Properties (P: Tall_Point) is
   begin
      Show_Properties (Point (P));
      Ada.Text_Io.Put_Line
        ("Height =>" & Real'Image (P.Height));
   end Show_Properties;

   procedure Show_Type (P : Point'Class) is
   begin
      Ada.Text_Io.Put_Line
        ("Type => " & Ada.Tags.External_Tag (P'Tag));
   end Show_Type;

end Points;

with Ada.Text_Io;
with Ada.Unchecked_Deallocation;
with Points;
procedure Test_Points is

   -- Since an object of Points.Point'Class must be constrained at the time
of
   -- declaration to some one of the types derived from Points.Point, and
   -- therefore cannot be re-used for other types derived from Points.Point,
   -- we use an access object, instead.  But first, we declare the type of
   -- that access object, as well as a deallocation procedure for it.
   type Point_Class_Access is access all Points.Point'Class;

   procedure Free is new Ada.Unchecked_Deallocation
     (Object => Points.Point'Class,
      Name   => Point_Class_Access);

   -- We do not need to initialize this access object here, but we do so
   -- just to illustrate that it can be done.
   P_Access : Point_Class_Access := new Points.Tall_Point'(3.0, 4.0, 5.0);

begin

   -- Note that this is _not_ a dispatching call, because the procedure's
   -- formal parameter is of a class-wide type.
   Points.Show_Type (P_Access.all);

   -- Note that this _is_ a dispatching call, because the object is of a
   -- class-wide type.
   Points.Show_Properties (P_Access.all);

   -- P_Access.Paint := Blue; Illegal P_Access accesses a Tall_Point object,
   -- so we must first deallocate the memory for the object, leaving it free
   -- to access another object of a type derived from Points.Point.
   Free (P_Access);

   P_Access := new Points.Painted_Point'(3.0, 4.0, Points.Blue);

   Points.Show_Type (P_Access.all);
   Points.Show_Properties (P_Access.all);

end Test_Points;

--------- end source code ------







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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00     ` Nick Roberts
@ 1999-02-06  0:00       ` Nick Roberts
  0 siblings, 0 replies; 34+ messages in thread
From: Nick Roberts @ 1999-02-06  0:00 UTC (permalink / raw)


To be finicky, I should have said, for the example call

   Something(A,...);

that if A has a static type, the correct Something is selected statically as
a part of normal overload resolution. It is only if A has a dynamic type
(i.e. it is an object of a class-wide type) that the dynamic selection of
Something occurs. It is only the dynamic selection which is called
'dispatching'.

-------------------------------------------
Nick Roberts
-------------------------------------------







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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00 ` How to write TYPECASE in Ada 95? David C. Hoos, Sr.
@ 1999-02-06  0:00   ` Matthew Heaney
  1999-02-06  0:00     ` Matthew Heaney
                       ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Matthew Heaney @ 1999-02-06  0:00 UTC (permalink / raw)


"David C. Hoos, Sr." <david.c.hoos.sr@ada95.com> writes:

> procedure Test_Points is
> 
>    -- Since an object of Points.Point'Class must be constrained at the time
> of
>    -- declaration to some one of the types derived from Points.Point, and
>    -- therefore cannot be re-used for other types derived from Points.Point,
>    -- we use an access object, instead.  But first, we declare the type of
>    -- that access object, as well as a deallocation procedure for it.
>    type Point_Class_Access is access all Points.Point'Class;
> 
>    procedure Free is new Ada.Unchecked_Deallocation
>      (Object => Points.Point'Class,
>       Name   => Point_Class_Access);
> 
>    -- We do not need to initialize this access object here, but we do so
>    -- just to illustrate that it can be done.
>    P_Access : Point_Class_Access := new Points.Tall_Point'(3.0, 4.0, 5.0);


Note that there's another way to illustrate these concepts, that does
not require heap.  Just use a declare block to declare each new kind of
point, as follows:

with Ada.Text_Io;
with Ada.Unchecked_Deallocation;
with Points; use Points;
procedure Test_Points is
begin

   declare
      P : Tall_Point := (3.0, 4.0, 5.0);
   begin
      Points.Show_Type (P);
      Points.Show_Properties (Point'Class (P));
   end;

   declare
      P : Painted_Point := (3.0, 4.0, Points.Blue);
   begin
      Points.Show_Type (P);
      Points.Show_Properties (Point'Class (P));
   end;

end Test_Points;



Declare blocks are your friend.  Unnecessary use of heap is your enemy.





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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00   ` Matthew Heaney
@ 1999-02-06  0:00     ` Matthew Heaney
  1999-02-06  0:00     ` Matthew Heaney
  1999-02-09  0:00     ` David C. Hoos, Sr.
  2 siblings, 0 replies; 34+ messages in thread
From: Matthew Heaney @ 1999-02-06  0:00 UTC (permalink / raw)


Matthew Heaney <matthew_heaney@acm.org> writes:

> Note that there's another way to illustrate these concepts, that does
> not require heap.  Just use a declare block to declare each new kind of
> point, as follows:

Here is yet another way to do this, by declaring the objects to be type
Point'Class.  This is probably closer to David's original example.

Like my earlier post, the example here doesn't require the use of heap.


with Ada.Text_Io;
with Ada.Unchecked_Deallocation;
with Points; use Points;
procedure Test_Points is
begin

   declare
      P : Point'Class := Tall_Point'(3.0, 4.0, 5.0);
   begin
      Points.Show_Type (P);
      Points.Show_Properties (P);
   end;

   declare
      P : Point'Class := Painted_Point'(3.0, 4.0, Points.Blue);
   begin
      Points.Show_Type (P);
      Points.Show_Properties (P);
   end;

end Test_Points;









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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00   ` Matthew Heaney
  1999-02-06  0:00     ` Matthew Heaney
@ 1999-02-06  0:00     ` Matthew Heaney
  1999-02-09  0:00     ` David C. Hoos, Sr.
  2 siblings, 0 replies; 34+ messages in thread
From: Matthew Heaney @ 1999-02-06  0:00 UTC (permalink / raw)


Matthew Heaney <matthew_heaney@acm.org> writes:

> with Points; use Points;
> procedure Test_Points is
> begin
> 
>    declare
>       P : Tall_Point := (3.0, 4.0, 5.0);
>    begin
>       Points.Show_Type (P);
>       Points.Show_Properties (Point'Class (P));
>    end;
> 
>    declare
>       P : Painted_Point := (3.0, 4.0, Points.Blue);
>    begin
>       Points.Show_Type (P);
>       Points.Show_Properties (Point'Class (P));
>    end;
> 
> end Test_Points;


I should have pointed out that you don't actually need to dispatch
Show_Properties.  At the invocation, you know the specific type of the
point, so why convert it to the class-wide type?

procedure Test_Points is
begin

   declare
      P : Tall_Point := (3.0, 4.0, 5.0);
   begin
      Points.Show_Type (P);
      Points.Show_Properties (P);
   end;

   declare
      P : Painted_Point := (3.0, 4.0, Points.Blue);
   begin
      Points.Show_Type (P);
      Points.Show_Properties (P);
   end;

end Test_Points;


The object model of Ada95 was designed to allow the caller to choose
whether dispatching occurs.  All the calls in the example above are
static, which is all they need to be.









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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00   ` Matthew Heaney
  1999-02-06  0:00     ` Matthew Heaney
  1999-02-06  0:00     ` Matthew Heaney
@ 1999-02-09  0:00     ` David C. Hoos, Sr.
  2 siblings, 0 replies; 34+ messages in thread
From: David C. Hoos, Sr. @ 1999-02-09  0:00 UTC (permalink / raw)



Matthew Heaney wrote in message ...
>"David C. Hoos, Sr." <david.c.hoos.sr@ada95.com> writes:
<large-snip>
>
>Declare blocks are your friend.  Unnecessary use of heap is your enemy.

Agreed.  In fact, often the appropriate thing to do is use a declare block -- e.g., when reading from a stream, and the type is
unknown -- but in this case I was also attempting to show that the same _object_ could refer to any descendnts of the root class.








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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00   ` Ed Falis
  1999-02-06  0:00     ` Nick Roberts
@ 1999-02-17  0:00     ` Tom Moran
  1999-02-18  0:00       ` Matthew Heaney
  1999-02-19  0:00     ` Tom Moran
  2 siblings, 1 reply; 34+ messages in thread
From: Tom Moran @ 1999-02-17  0:00 UTC (permalink / raw)


Dispatching is certainly better than a case statement - if you use it.

Consider an existing package of the form:

package Grocer is
  type Fruit is abstract tagged ...
  type Apple is new Fruit ...
  ...
  type Watermelon is new Fruit ...
  ...
  function Best(Budget : in Money) return Fruit'class;
end Grocer;

And now you are writing a new package which, among other things, does

with Grocer;
 use Grocer;
package Meal is
  procedure Serve(Dish : in Apple);
  ...
  procedure Serve(Dish : in Watermelon);
end Meal;

Suppose a user wants, not unreasonably, to write
...
   Meal.Serve(Dish => Grocer.Best(Budget=>1.00));

Unless you can go back and modify Grocer, it appears you must include
in Meal
  procedure Serve_Fruit(Dish : in Fruit'class);
with a body like
  procedure Serve_Fruit(Dish : in Fruit'class) is
  begin
    if Dish in Apple'class then Serve(Apple(Dish));
    ...
    elsif Dish in Watermelon'class then Serve(Watermelon(Dish));
    else raise Heck;
    end if;
  end Serve_Fruit;

Is there a better way?





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

* Re: How to write TYPECASE in Ada 95?
  1999-02-18  0:00       ` Matthew Heaney
  1999-02-18  0:00         ` Tom Moran
@ 1999-02-18  0:00         ` robert_dewar
  1999-02-19  0:00           ` Nick Roberts
  1999-02-19  0:00           ` Tom Moran
  1999-02-18  0:00         ` Tom Moran
  2 siblings, 2 replies; 34+ messages in thread
From: robert_dewar @ 1999-02-18  0:00 UTC (permalink / raw)


tmoran@bix.com (Tom Moran) writes:
> Dispatching is certainly better than a case statement -
> if you use it.

I strongly disagree with this statement. This particular
bit of conventional wisdom is badly in error, and can lead
to unnecessarily obscure hard to maintain programs.

Case statements and dispatching represent two ways of
slicing a 2-D array of types vs operations. The use of
case statements may make it easier to add operations, the
use of dispatching may make it easier to add types. Which
is better depends on the particular situation.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own    




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

* Re: How to write TYPECASE in Ada 95?
  1999-02-17  0:00     ` Tom Moran
@ 1999-02-18  0:00       ` Matthew Heaney
  1999-02-18  0:00         ` Tom Moran
                           ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Matthew Heaney @ 1999-02-18  0:00 UTC (permalink / raw)


tmoran@bix.com (Tom Moran) writes:

> Dispatching is certainly better than a case statement - if you use it.
> 
> Consider an existing package of the form:
> 
> package Grocer is
>   type Fruit is abstract tagged ...
>   type Apple is new Fruit ...
>   ...
>   type Watermelon is new Fruit ...
>   ...
>   function Best(Budget : in Money) return Fruit'class;
> end Grocer;
> 
> And now you are writing a new package which, among other things, does
> 
> with Grocer;
>  use Grocer;
> package Meal is
>   procedure Serve(Dish : in Apple);
>   ...
>   procedure Serve(Dish : in Watermelon);
> end Meal;
> 
> Suppose a user wants, not unreasonably, to write
> ...
>    Meal.Serve(Dish => Grocer.Best(Budget=>1.00));
> 
> Unless you can go back and modify Grocer, it appears you must include
> in Meal
>   procedure Serve_Fruit(Dish : in Fruit'class);
> with a body like
>   procedure Serve_Fruit(Dish : in Fruit'class) is
>   begin
>     if Dish in Apple'class then Serve(Apple(Dish));
>     ...
>     elsif Dish in Watermelon'class then Serve(Watermelon(Dish));
>     else raise Heck;
>     end if;
>   end Serve_Fruit;
> 
> Is there a better way?


It seems like the real problem in your example is that Fruit doesn't
include any primitive operations for Serve'ing.

If you want to extend a type with arbitrary behavior, you could take a
look at using the Visitor pattern.  Ada implementations of this pattern
are available at the ACM patterns archive.

<http://www.acm.org/archives/patterns.html>








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

* Re: How to write TYPECASE in Ada 95?
  1999-02-18  0:00       ` Matthew Heaney
  1999-02-18  0:00         ` Tom Moran
  1999-02-18  0:00         ` robert_dewar
@ 1999-02-18  0:00         ` Tom Moran
  1999-02-18  0:00           ` Matthew Heaney
  2 siblings, 1 reply; 34+ messages in thread
From: Tom Moran @ 1999-02-18  0:00 UTC (permalink / raw)


>If you want to extend a type with arbitrary behavior, you could take a
>look at using the Visitor pattern.  Ada implementations of this pattern
>are available at the ACM patterns archive.

><http://www.acm.org/archives/patterns.html>
Am I looking at the right place?  I see

>package body Equipment.Pricing is


>   function Get_Total_Price
>     (Equipment : Root_Equipment'Class) return Dollars is
>   begin
>      if Equipment in Floppy_Disk then

>         declare
>            Disk : Floppy_Disk renames Floppy_Disk (Equipment);
>         begin
>            return Get_Price_Of_Floppy_Disk (Disk);
>         end;

>      elsif Equipment in Hard_Disk then

>         declare
>            Disk : Hard_Disk renames Hard_Disk (Equipment);
>         begin
>            return Get_Price_Of_Hard_Disk (Disk);
>         end;
which surely looks pretty similar to

> procedure Serve_Fruit(Dish : in Fruit'class) is
>  begin
>    if Dish in Apple'class then Serve(Apple(Dish));
>    ...
>    elsif Dish in Watermelon'class then Serve(Watermelon(Dish));




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

* Re: How to write TYPECASE in Ada 95?
  1999-02-18  0:00       ` Matthew Heaney
@ 1999-02-18  0:00         ` Tom Moran
  1999-02-18  0:00         ` robert_dewar
  1999-02-18  0:00         ` Tom Moran
  2 siblings, 0 replies; 34+ messages in thread
From: Tom Moran @ 1999-02-18  0:00 UTC (permalink / raw)


>> Unless you can go back and modify Grocer, 
>It seems like the real problem in your example is that Fruit doesn't
>include any primitive operations for Serve'ing.
Right.

>If you want to extend a type with arbitrary behavior, you could take a
>look at using the Visitor pattern.  Ada implementations of this pattern
>are available at the ACM patterns archive.

><http://www.acm.org/archives/patterns.html>
Thanks, I'll take a look there.






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

* Re: How to write TYPECASE in Ada 95?
  1999-02-18  0:00         ` Tom Moran
@ 1999-02-18  0:00           ` Matthew Heaney
  0 siblings, 0 replies; 34+ messages in thread
From: Matthew Heaney @ 1999-02-18  0:00 UTC (permalink / raw)


tmoran@bix.com (Tom Moran) writes:

> >If you want to extend a type with arbitrary behavior, you could take a
> >look at using the Visitor pattern.  Ada implementations of this pattern
> >are available at the ACM patterns archive.
> 
> ><http://www.acm.org/archives/patterns.html>
> Am I looking at the right place?  I see
> 
> >package body Equipment.Pricing is
> 
> 
> >   function Get_Total_Price
> >     (Equipment : Root_Equipment'Class) return Dollars is
> >   begin
> >      if Equipment in Floppy_Disk then
...
> which surely looks pretty similar to
> 
> > procedure Serve_Fruit(Dish : in Fruit'class) is
> >  begin
> >    if Dish in Apple'class then Serve(Apple(Dish));
> >    ...
> >    elsif Dish in Watermelon'class then Serve(Watermelon(Dish));



Indeed, you are correct.  The was the last of 3 versions of the visitor
pattern I sent to the list, and I discuss the pros and cons of each
approach in the accompanying text.







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

* Re: How to write TYPECASE in Ada 95?
  1999-02-06  0:00   ` Ed Falis
  1999-02-06  0:00     ` Nick Roberts
  1999-02-17  0:00     ` Tom Moran
@ 1999-02-19  0:00     ` Tom Moran
  1999-02-19  0:00       ` Tom Moran
  1999-02-23  0:00       ` Samuel Mize
  2 siblings, 2 replies; 34+ messages in thread
From: Tom Moran @ 1999-02-19  0:00 UTC (permalink / raw)


>>> I thought a good part of the point of tagged types
>>> (and support for polymorphism in other OOP's) was
>>> exactly to avoid this kind of code. (series of if-elsif)

>>Dispatching is certainly better than a case statement - if you use it.
>>Consider an existing package of the form: (example of dispatching being inappropriate)

>tmoran@bix.com (Tom Moran) writes:
>> Dispatching is certainly better than a case statement -
>> if you use it.
>I strongly disagree with this statement. This particular
>bit of conventional wisdom is badly in error, and can lead
>to unnecessarily obscure hard to maintain programs.
>Case statements and dispatching represent two ways of
  I see you strongly agree that dispatching is not always the
solution, and a case statement, for instance, is more appropriate.
But in the situation at hand, the only thing apparently available is
the original poster's original if-elsif list, with the usual hazards
of left out or overlapping cases.  Was something like Modula 3's
"Typecase" considered for Ada 95?  Are there problems with it?  




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

* Re: How to write TYPECASE in Ada 95?
  1999-02-19  0:00     ` Tom Moran
@ 1999-02-19  0:00       ` Tom Moran
  1999-02-23  0:00       ` Samuel Mize
  1 sibling, 0 replies; 34+ messages in thread
From: Tom Moran @ 1999-02-19  0:00 UTC (permalink / raw)


Sorry, the above was a response to Dewar, not Falis.




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

* Re: How to write TYPECASE in Ada 95?
  1999-02-18  0:00         ` robert_dewar
  1999-02-19  0:00           ` Nick Roberts
@ 1999-02-19  0:00           ` Tom Moran
  1 sibling, 0 replies; 34+ messages in thread
From: Tom Moran @ 1999-02-19  0:00 UTC (permalink / raw)


>The use of
>case statements may make it easier to add operations, the
>use of dispatching may make it easier to add types. Which
>is better depends on the particular situation.
  And what do you suggest for the case where an existing system has
been designed with tagged records to make it easy to add types, and
you find it necessary to add an operation?  Must one then add a
typecase, pardon me, an if-elsif series of "if x in variant_1
then..."?  Or is there a better way (short of modifying the original
system, of course)?




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

* Re: How to write TYPECASE in Ada 95?
  1999-02-18  0:00         ` robert_dewar
@ 1999-02-19  0:00           ` Nick Roberts
  1999-02-19  0:00           ` Tom Moran
  1 sibling, 0 replies; 34+ messages in thread
From: Nick Roberts @ 1999-02-19  0:00 UTC (permalink / raw)


robert_dewar@my-dejanews.com wrote in message
<7ai3m2$4t0$1@nnrp1.dejanews.com>...
|tmoran@bix.com (Tom Moran) writes:
|> Dispatching is certainly better than a case statement -
|> if you use it.
|
|I strongly disagree with this statement. This particular
|bit of conventional wisdom is badly in error, and can lead
|to unnecessarily obscure hard to maintain programs.
|
|Case statements and dispatching represent two ways of
|slicing a 2-D array of types vs operations. The use of
|case statements may make it easier to add operations, the
|use of dispatching may make it easier to add types. Which
|is better depends on the particular situation.


I believe I illustrated in a previous post the reason why using dispatching
is sometimes 'overkill'.

To recap briefly, imagine a large tree of types: T; Ta; Tb; Taa; Tab; Tba;
Tbb; Taaa; Taab; Taba; Tabb; and so on. T is at the top. Ta and Tb are
derived from T. Taa and Tab are derived from Ta. You get the picture.

Now imagine a procedure P(X: in out T'Class) which contains a large number
of lines of processing, and which has a slight variation in the middle just
for the types Tabaab and Tbbaba, say. It only needs an 'if' or 'case', in
the appropriate place, to distinguish these types and do the special actions
for them.

Now consider, instead, having P(X: in out T), and then having to overload
this procedure for each and every type Ta, Tb, Taa, etc., etc.. Lots of
types times many lines of code, most of which are all the same. Disastrous.
Even if the fixed parts are factored out, you still have to declare lots of
overloadings; it's just not worth it!

Finally, consider a procedure Q(X: in out T) which performs an operation
that has a substantially different implementation for each and every
different type. Dispatching for procedure Q makes a lot of sense.

Dispatching is very often an excellent approach. But, it is definitely not
_always_ the best solution!

-------------------------------------
Nick Roberts

'The time has come,' the Walrus said,
  'To talk of many things:
Of shoes--of ships--and sealing wax--
  Of cabbages--and kings--
And why the sea is boiling hot--
  And whether pigs have wings.'
                        Lewis Carroll
          "Through the Looking Glass"
-------------------------------------








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

* Re: How to write TYPECASE in Ada 95?
  1999-02-19  0:00     ` Tom Moran
  1999-02-19  0:00       ` Tom Moran
@ 1999-02-23  0:00       ` Samuel Mize
  1999-02-23  0:00         ` Question (was Re: How to write TYPECASE in Ada 95?) Mike Silva
  1 sibling, 1 reply; 34+ messages in thread
From: Samuel Mize @ 1999-02-23  0:00 UTC (permalink / raw)


Tom Moran <tmoran@bix.com> wrote:
> But in the situation at hand, the only thing apparently available is
> the original poster's original if-elsif list, with the usual hazards
> of left out or overlapping cases.  Was something like Modula 3's
> "Typecase" considered for Ada 95?  Are there problems with it?  

I've waited a couple of days, and more knowledgeable people haven't
replied.  Hopefully they'll correct any errors in the following.
(Often the best way to get info on the net is not to post a question,
but to post a wrong answer...)  Anyway, here's my understanding.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
A "typecase" type of semantic was indeed considered for Ada 95.

There are four problems with a "typecase" capability, from an Ada
point of view.  The first three consider the meaning of the constructs
involved; the last considers the efficiency and optimization of these
constructs.

1. Since you cannot check for complete and non-overlapping coverage,
the "typecase" statement adds no advantage over an "if-elsif" cascade.

It's appealing to think that you could check coverage of the class
hierarchy, but you couldn't.

Since a class can be added by the later compilation of a library
package, you cannot check for complete coverage of all tags in the
hierarchy.

Nor can you usefully check for non-overlapping coverage in most cases.
If the root type of the hierarchy is not abstract, it must be covered.
Non-overlapping coverage would then keep you from adding any other
tags, and you'd have a block instead of a case statement.

Even if your class hierarchy is abstract down to some level, it
greatly reduces the utility of a "typecase" construct to prevent
overlapping classes.  If one type is a special case, you must call
it out.  You then cannot handle its parent type's (overlapping) class
as a general case.  So, if a library package later extends that parent
type, your typecase will consider the extended type to be an "others"
case, not a member of the parent class.

So a "typecase" construct can add no semantic value over an "if-elsif"
cascade.  It would just be "syntactic sugar" -- a convenience, but
no real addition to the expressive power of the language.

And, it would give the unsophisticated user a deceptive appearance of
checking class coverage.

2. Adding a "typecase" meaning to "case" would alter the underlying
meaning of "case".

A "case" statement enumerates all the possible options that it
covers -- it lists them out explicitly, so a later programmer can see
what they are.  "Others" is allowed only because you can enumerate out
what it means if you need to.

This is not possible for a typecase statement.  A new type can be
added by any arbitrary package, later.  So, an extended "case" for
tags would have a different basic meaning than any other "case"
statement.  This would be confusing.

Of course, this point only argues against extending "case," not
against adding a new construct.

3. A "typecase" would encourage dangerous usage in the face of
programming by extension.

Remember, tagged types are NOT a facility for object-oriented
programming.  Together with other facilities in the language, they
support that idiom.  However, tagged types are a facility for
programming by extension, in a much more general form than many
object-oriented languages provide.

Ideally, whenever a tagged type is extended, you could add whatever
code changes are needed to accomodate it at the location of the
extension.  No changes in the pre-existing system would be needed.

If there are class-wide operations that may be applied to the new
type, this is not the case.  These must be checked to ensure that
they are still correct.  If, internally, such an operation branches
on a tag value, the pre-existing system may need to be altered -- and
the attempt to program by extension has, to some extent, failed.  This
is especially a problem if the body of the class-wide operation is
hidden from the programmer, for instance as part of a proprietary
package for which only the spec is provided.

So branching on tag values is dangerous -- although not dangerous
enough to merit an "Unchecked_" prefix.  Adding a "typecase" would
implicitly condone widespread use of this idiom, which should only be
used after careful consideration of other alternatives, and of the
risk involved.  (Which is not to say it shouldn't be used.)

4. It would take sophisticated compiler support to make a "typecase"
efficient.  Since both the "case" statement and tagged types are
intended to be very efficient, this could be a damaging surprise to
the user.

"Case" should just compute the expression and do an indirect jump.
Tagged types should dispatch very fast with a jump table.  But the
combination of these two would require an arbitrarily-long search of
the class hierarchy.  If this occurs in a tight "heartbeat" loop, it
may be a significant performance issue.

Now it seems to me (without deep analysis, I admit) that a clever
compiler suite could build up a static jump table for each case
statement at build time, once it knew what tags would have to be
considered.  This could run pretty efficiently, and shouldn't take up
*too* much space.

But, the Ada 95 team was weighing a lot of alternatives, many of which
require quite clever compilers.  I assume that this was not considered
important enough to merit such a requirement for cleverness.  In
particular, I doubt that they wanted to add a requirement for the
binder to generate code, and without such fancy-and-late code
generation a "typecase" would be surprisingly slow.  Worse, its
slowness would vary radically between these two classes of compiler.

Use of a separate keyword like "typecase" might reduce the surprise
issue.  On the other hand, many programmers would expect such a
construct to be similar to "case" and would not delve deeply into the
language design issues.  And, the Ada 95 language designers tried to
keep new keywords to a minimum, so they had to add something really
important to be considered.

Best,
Sam Mize

-- 
Samuel Mize -- smize@imagin.net (home email) -- Team Ada
Fight Spam: see http://www.cauce.org/ \\\ Smert Spamonam




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

* Question (was Re: How to write TYPECASE in Ada 95?)
  1999-02-23  0:00       ` Samuel Mize
@ 1999-02-23  0:00         ` Mike Silva
  1999-02-24  0:00           ` (long) programming by extension (was: " Samuel Mize
                             ` (2 more replies)
  0 siblings, 3 replies; 34+ messages in thread
From: Mike Silva @ 1999-02-23  0:00 UTC (permalink / raw)



Samuel Mize wrote in message <7av52o$62g@news3.newsguy.com>...
<...>
>Remember, tagged types are NOT a facility for object-oriented
>programming.  Together with other facilities in the language, they
>support that idiom.  However, tagged types are a facility for
>programming by extension, in a much more general form than many
>object-oriented languages provide.

This intrigues me greatly, but being an Ada neophyte and not having that
much OOP background in general I don't know what it means.  Would anybody
care to offer an explanation, or point me in the direction of one.  Thanks
much.

Mike Silva








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

* Re: (long) programming by extension
  1999-02-24  0:00           ` (long) programming by extension (was: " Samuel Mize
@ 1999-02-24  0:00             ` Samuel Mize
  1999-02-25  0:00               ` (shorter and new) " Samuel Mize
  0 siblings, 1 reply; 34+ messages in thread
From: Samuel Mize @ 1999-02-24  0:00 UTC (permalink / raw)


The example I used to describe programming by extension is also used
to describe object-oriented programming.  So it was a poor choice to
show the difference.  However, there IS a difference.

I'll try again.

Suppose you are coding a message handler which will get messages in
one format from many interfaces, some of which are not yet known, and
perform some complex computation.  You can define each interface to
have a "get" procedure, and use a tagged type to pick the right "get."

    package No_Interface is
        type Use_None is tagged null record;
        type Interface_Selector is access all Use_Nothing'Class;

        -- this will raise an exception if called,
        -- or maybe return a default value

        procedure Get (Interface: Use_Nothing;
                       Message: Data_Format -- defined elsewhere
                       );

    end No_Interface;
    - - - - - - - - - - - - - - - - - - - - -
    with No_Interface;
    package Disk_Interface is
        type Use_Disk is new No_Interface.Use_None with null record;

        procedure Get (Interface: Use_Disk;
                       Message: Data_Format);
    end package;
    - - - - - - - - - - - - - - - - - - - - -
    with No_Interface;
    package Serial_Interface is
        type Use_Serial is new No_Interface.Use_None with null record;

        procedure Get (Interface: Use_Serial;
                       Message: Data_Format);
    end package;
    - - - - - - - - - - - - - - - - - - - - -
    with No_Interface; use No_Interface;
    procedure Message_Handler (Current: Interface_Selector) is
       D: Data_Format;
    begin
       -- some complex computation involving several records
       for I in whatever_range loop
          Get (Current.all, D);
            ...
            if D.Continued then
                Get (Current.all, D);
                ...
       end loop;
    end Message_Handler;
          
In no case will the type Use_[whatever] contain any data.

You can add interfaces as you need to, and never have to recode -- or
even re-compile -- Message_Handler.

I would certainly NOT call this object-oriented programming.  It's sort
of an "infinite case statement."  But it does take advantage of the
Ada 95 facilities for programming by extension.

In a real-world application, something as significant as a major device
interface probably WOULD be coded as an "object," if you're using
object-oriented technology.  This is a contrived example.

I HAVE used tagged types to generate such an "infinite case statement,"
but it was buried in an obscure and proprietary system, so it would be
neither clear nor legal for me to reproduce the code.

Best,
Sam Mize

-- 
Samuel Mize -- smize@imagin.net (home email) -- Team Ada
Fight Spam: see http://www.cauce.org/ \\\ Smert Spamonam




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

* Re: Question (was Re: How to write TYPECASE in Ada 95?)
  1999-02-23  0:00         ` Question (was Re: How to write TYPECASE in Ada 95?) Mike Silva
  1999-02-24  0:00           ` (long) programming by extension (was: " Samuel Mize
  1999-02-24  0:00           ` Question (was Re: How to write TYPECASE in Ada 95?) Nick Roberts
@ 1999-02-24  0:00           ` Samuel T. Harris
  1999-02-24  0:00             ` Matthew Heaney
  2 siblings, 1 reply; 34+ messages in thread
From: Samuel T. Harris @ 1999-02-24  0:00 UTC (permalink / raw)


Mike Silva wrote:
> 
> Samuel Mize wrote in message <7av52o$62g@news3.newsguy.com>...
> <...>
> >Remember, tagged types are NOT a facility for object-oriented
> >programming.  Together with other facilities in the language, they
> >support that idiom.  However, tagged types are a facility for
> >programming by extension, in a much more general form than many
> >object-oriented languages provide.
> 
> This intrigues me greatly, but being an Ada neophyte and not having that
> much OOP background in general I don't know what it means.  Would anybody
> care to offer an explanation, or point me in the direction of one.  Thanks
> much.
> 
> Mike Silva

One of the attractive attributes of Ada is that facilities
are provided without attaching some taxonomy to the facility.
Frequently, a combination of facilities are required to
match a particular paradim. While this may appear to some
as form of "weak" support for that paradim, I see it as freeing
the language from the paradim du jour. I am free to combine
language elements to suit the mind set at hand without
fighting an ingrained taxonomy within the language itself.

This also enables the language to keep the features
orthogonal to each other. Because so many features and
constructions are available, their use together many times
calls for what appear to be archane rules to protect
the system being developed. The protection is desirable,
but the orthogonality of the constructions sometimes hides
the necessity of some of the rules.

If I was doing structured programming, I'd have a hard time
getting past the taxonomy enforced by C++ and other OOLs.
I don't have that problem with Ada.

As Samuel Mize says, tagged types provided a mechanism
for type extension. Since OOP relies upon type extension,
tagged types are a natural match. Packages provide encapsulation
and naming scope. Packages group things together. A OO class
is a grouping of a data structure type and its defined
operations. So a class must be a package defining a tagged
type and including all the primative operations on that
type. Both are required to implement a class.

Singular inheritance is directly supported by the language
through tagged types. Multiple inheritance, in several forms,
is supported by combining tagged types with other language
constructions such as generics. I believe Ada 95 Rational
provides an in-depth discussion on kinds multiple inheritance,
why they are not directly supported, and how achieve the
desired result.

I just wish Ada didn't use the term class-wide type.
It is a term with too much overloaded meaning.

Since you are an Ada neophyte, I recommand you
visit www.adahome.com and browse around. You'll
want to consider downloading the GNAT compiler for your
personal use at home. You may also consider getting
the Walnut Creek Ada CDROM which contains tons of
code and supporting documents which are not just
limited to Ada, but also include good software
engineering as well.

-- 
Samuel T. Harris, Principal Engineer
Raytheon, Scientific and Technical Systems
"If you can make it, We can fake it!"




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

* Re: Question (was Re: How to write TYPECASE in Ada 95?)
  1999-02-24  0:00           ` Samuel T. Harris
@ 1999-02-24  0:00             ` Matthew Heaney
  1999-02-24  0:00               ` Tucker Taft
  0 siblings, 1 reply; 34+ messages in thread
From: Matthew Heaney @ 1999-02-24  0:00 UTC (permalink / raw)


"Samuel T. Harris" <sam_harris@hso.link.com> writes:

> I just wish Ada didn't use the term class-wide type.
> It is a term with too much overloaded meaning.

The term "class" already had that meaning in Ada83: the class of float
point types, the class of integer types, etc.  It was Tucker's vision
for Ada95 that it preserve as much as possible that Ada83 way of doing
things.

I just wish Ada allowed the attribute T'Class for non-tagged types too.
That would be a way to solve the problem of simultaneous derivation.

For example, if New_Line had been declared something like this:

   procedure New_Line 
    (File    : in File_Type; 
     Spacing : in Positive_Count'Class := 1);

then if we did this:

  package P is

      type File_Type is new Text_IO.File_Type;

      type Positive_Count is new Text_IO.Positive_Count;

  end P;

then you'd get a New_Line at the point of declaration of P.File_Type
that works with type P.Positive_Count.







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

* (long) programming by extension (was: How to write TYPECASE in Ada 95?)
  1999-02-23  0:00         ` Question (was Re: How to write TYPECASE in Ada 95?) Mike Silva
@ 1999-02-24  0:00           ` Samuel Mize
  1999-02-24  0:00             ` (long) programming by extension Samuel Mize
  1999-02-24  0:00           ` Question (was Re: How to write TYPECASE in Ada 95?) Nick Roberts
  1999-02-24  0:00           ` Samuel T. Harris
  2 siblings, 1 reply; 34+ messages in thread
From: Samuel Mize @ 1999-02-24  0:00 UTC (permalink / raw)


Mike Silva <mjsilva@jps.net> wrote:
> 
> Samuel Mize wrote in message <7av52o$62g@news3.newsguy.com>...
> <...>
>>Remember, tagged types are NOT a facility for object-oriented
>>programming.  Together with other facilities in the language, they
>>support that idiom.  However, tagged types are a facility for
>>programming by extension, in a much more general form than many
>>object-oriented languages provide.
> 
> This intrigues me greatly, but being an Ada neophyte and not having that
> much OOP background in general I don't know what it means.  Would anybody
> care to offer an explanation, or point me in the direction of one.  Thanks
> much.

I don't have an appropriate pointer to an existing discussion (I'd be
interested to see them too).

Instead of replying by email, I'll be long-winded here on the net, so
others can chime in with additions or corrections.  Note that the
early part of this covers the basics of defining abstractions in
functional programming, to motivate building up to programming by
extension toward the end.

- - - - -
Programming by Extension means programming a large system so that new
processing cases can be handled by adding new code, without having to
recode any existing modules.  Language support is extremely helpful
for true programming by extension.

Object-oriented development is a very specific way of analyzing,
designing and coding a system.  It provides a way to program by
extension -- that's one of its selling points -- but it brings along
a lot of other baggage too.

Sometimes you want that baggage.  That's why "object-oriented"
technology exists.  But sometimes you just want to do plain functional
programming, and be able to extend the system later without having to
recode the existing part.  Ada supports this also.

The Ada 95 Rationale describes how Ada supports programming by
extension, but it doesn't really define the term.  Here's a concrete
example of programming by extension.  I'll motivate it by showing the
intermediate manual steps that lead to programming by extension.

Consider a windowing user interface.  You have a main loop that looks
at events, like mouse clicks, and calls the appropriate routine to
handle the event, passing that routine a pointer to the window that
owns the part of the screen where the event occurred.

The simple-minded approach would be to put all the code into the loop.
Applying functional abstraction, we can define some procedures like
Draw and Process_Mouse_Click, and call those procedures in the event
loop.  Now, if we put them into a separate package, we can change the
procedures without having to recode or recompile the loop:

   package Windows is
      type Window is ...

      procedure Draw (W: Window);
      procedure Process_Mouse_Click (W: Window);
   end Windows;
   - - - - - -
   with Windows;
   procedure Event_Loop is
      W: Windows.Window;
      E: Event; -- defined somewhere else
   begin
      loop
         Get_Event (E);
         Get_Current_Window (W);
         case E is
            when Draw_Window => Draw (W);
            when Click => Process_Mouse_Click (W);
         end case;
      end loop;
   end Event_Loop;

However, if you add a new kind of window, you will change the Window
type.  That means you will have to recompile the event loop, and
you will have to recode all the procedures in package Windows.  That's
not a big deal for this small, trivial example, but in a large system
it can be a significant cost.

Note that Ada is often used in life-critical systems like avionics,
where each unit goes through a long and expensive validation of the
compiled object code.  This must be redone if the unit is recompiled,
even if the source code is not changed.

So, we want to completely isolate the event loop.  We can do this by
making Window a pointer that can point at any kind of window, so that
Event_Loop won't have to be recompiled when we add a new kind of window.

In C, you would do that by declaring Window as a pointer to void.  The
actual window data structures would all start with an integer.  The
window procedures, like Draw, would typecast that to pointer-to-integer
to see the integer, and use that integer to pick the right type to cast
the pointer to in order to handle the event.  This is (very) roughly
how the X-windows system handles windows.

You can do the same thing in Ada 95 or C++, but it's wiser to use the
language-provided features.  I'll describe Ada's in a moment.

And even then, you'll still have a big case statement full of
type-specific code in each window routine.

The next step is to make the routines in Windows nothing BUT the case
statement, and extract all the code out to type-specific packages for
each window type.  Something like:

   package Basic_Window is
      type Window is
         record
           Kind: Integer := 1;
           ...
         end record;
      procedure Draw (W: Window);
      procedure Process_Mouse_Click (W: Window);
   end Basic_Window;
   - - - - - -
   package Alert_Window is -- border flashes red
      type Window is
         record
           Kind: Integer := 2;
           ...
         end record;
      procedure Draw (W: Window);
      procedure Process_Mouse_Click (W: Window);
   end Alert_Window;
   - - - - - -
   package Windows is
      type Window is private;

      procedure Draw (W: Window);
      procedure Process_Mouse_Click (W: Window);
   private
      type Hidden_Window_Type;
      type Window is access Hidden_Window_Type;
   end Windows;
   - - - - - -
   with Basic_Window;
   with Alert_Window;
   package body Windows is

      type Hidden_Window_Type is
         record
           Kind: Integer := 2;
         end record;

      type Kind_Of_Window is (Basic, Alert);

      -- - - - -
      function To_Basic (W: Hidden_Window_Type)
         return Basic_Window.Window is ...
      -- probably an instance of Unchecked_Conversion
      
      ----------
      procedure Draw (W: Window) is
      begin
         case W.all.Kind is
            when 1
              => Basic_Window.Draw (To_Basic (W.all));
            ...

Now, if you add a new kind of window, you create a new package and
update the case statements in Windows.  You only compile the new
package and the body of Windows.  You have almost achieved programming
by extension; you have come about as close as possible manually.

The Programming-by-Extension facilities in Ada 95 let you eliminate
the package Windows.  If Basic_Window.Window is a "tagged" type, your
event loop's calls to Basic_Window.Draw will be interpreted as being
calls to the appropriate Draw for the actual type of Window involved.

Another feature of the Programming-by-Extension facilities in Ada 95
is that, when you derive a new type from a tagged type, you can re-use
the "parent" type's procedures, if they still apply.  For example,
suppose that both Basic and Alert windows process mouse clicks the
same way; the only difference is how they draw the window.  Your code
would look like:

   package Basic_Window is
      type Window is tagged
         record
           ...
         end record;

      procedure Draw (W: Window);
      procedure Process_Mouse_Click (W: Window);
   end Basic_Window;

   - - - - - -
   with Basic_Window;
   package Alert_Window is -- border flashes red

      type Window is new Basic_Window.Window with
           Flashes_Per_Second: Integer;
         end record;

      -- Draw is "inherited" -- the Draw from package Basic_Window
      --    will be used for objects of this type

      procedure Process_Mouse_Click (W: Window);

   end Alert_Window;

   ----
   with Basic_Window;
   procedure Event_Loop is
      E: Event; -- defined somewhere else

      function Get_Current_Window
         return Basic_Window.Window'Class is ...

      procedure Handle_Event (W: Basic_Window.Window'Class) is
      begin
         case E is
            when Draw_Window => Basic_Window.Draw (W);
            when Click => Basic_Window.Process_Mouse_Click (W);
         end case;
      end Handle_Event;

   begin
      loop
         Get_Event (E);
         Handle_Event (Get_Current_Window);
      end loop;
   end Event_Loop;

Note that, in Event_Loop, we don't know how much memory an arbitrary
window may need, so we can't just declare an object of type
Basic_Window.Window'Class.  Instead, we make it a parameter to a
helper procedure.  Its size may vary at run time, but the compiler
and run-time system take care of that "behind the scenes."

NOW we have programming by extension available for this system!

To add a new kind of window, we create a new type that extends
Basic_Window.Window (or Alert_Window.Window).  We don't have to recode,
or even recompile, ANYTHING -- not the window packages, not event loop,
NOTHING!  The Ada compiler and run-time take care of calling the right
Draw or Process_Mouse_Click routines, based on the actual type of the
window returned by Get_Current_Window.

I hope you find this extended sketch useful.  

You can do the same general thing in C++, but you have to make the
window type a class, and each new window type a subclass of that
class.  An instance of the class is an "object."  The terms "class"
and "object" carry a lot of connotations that may not be true in all
cases, for instance that the item in question is a discrete entity
that exists in its own right, or that the "classes" involved form a
meaningful taxonomy and not just a hierarchy that reflects some
implementation concern.

I believe there are semantic constraints and extra coding effort if
you use C++ for non-object-oriented programming by extension, but I am
not familiar enough with the language to give you specific details.
(Anyone else?)

Best,
Sam Mize

-- 
Samuel Mize -- smize@imagin.net (home email) -- Team Ada
Fight Spam: see http://www.cauce.org/ \\\ Smert Spamonam




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

* Re: Question (was Re: How to write TYPECASE in Ada 95?)
  1999-02-24  0:00             ` Matthew Heaney
@ 1999-02-24  0:00               ` Tucker Taft
  0 siblings, 0 replies; 34+ messages in thread
From: Tucker Taft @ 1999-02-24  0:00 UTC (permalink / raw)


Matthew Heaney (matthew_heaney@acm.org) wrote:

: ...
: I just wish Ada allowed the attribute T'Class for non-tagged types too.

We had those for a while during the 9X process, but they were considered
a bit too "radical" ;-).  They survived as the "universal types" for
numeric types, but the more general notion of <non-tagged>'Class
didn't make the "cut."

--
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Distributed IT Solutions  (www.averstar.com/tools)
AverStar (formerly Intermetrics, Inc.)   Burlington, MA  USA




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

* Re: Question (was Re: How to write TYPECASE in Ada 95?)
  1999-02-23  0:00         ` Question (was Re: How to write TYPECASE in Ada 95?) Mike Silva
  1999-02-24  0:00           ` (long) programming by extension (was: " Samuel Mize
@ 1999-02-24  0:00           ` Nick Roberts
  1999-02-24  0:00           ` Samuel T. Harris
  2 siblings, 0 replies; 34+ messages in thread
From: Nick Roberts @ 1999-02-24  0:00 UTC (permalink / raw)


Object oriented programming is considered by many to be more (or entirely)
about a programming methodology (a 'mentality', if you like), rather than
just a particular set of programming tools, or the characteristics of a
particular programming language. It also has its own argot: you use
'objects' to model real-life entities; you organise those objects into the
hierarchies - or 'classes' - their real-world analogues exhibit; objects
interact by sending each other 'messages'; and so on.

I think Ada 95 was always designed to provide sufficient language 'tools' to
support an object-oriented methodology, without actually imposing that (or
any other) methodology (or terminology), as such. You can use tagged types
simply for 'programming-by-extension', without having to subscribe to the
whole object oriented 'mentality'. Or, if you wish, you can use them as a
part of a full-blooded object-oriented design approach. As you wish.

The thing that has always stood out to me about object oriented designs is
that a good design is almost always directly transferable from one
programming language to another. There's definitely something fundamental
about it. A good OO design can be a great design. Possibly the best thing
about it is that it persuades programmers to design at a higher level of
abstraction than they otherwise would. It's just a pity that all the
ballyhoo surrounding the subject at the moment could easily lead a lot of
people to think nothing of it.

-------------------------------------
Nick Roberts
-------------------------------------








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

* Re: (shorter and new) programming by extension
  1999-02-25  0:00               ` (shorter and new) " Samuel Mize
@ 1999-02-25  0:00                 ` Mike Silva
  1999-02-26  0:00                   ` Samuel Mize
  0 siblings, 1 reply; 34+ messages in thread
From: Mike Silva @ 1999-02-25  0:00 UTC (permalink / raw)



Samuel Mize wrote in message <7b49mm$t7q@news1.newsguy.com>...
>I'm too pedantic to leave adequate-enough alone, so I've refined my
>example of non-object-oriented programming by extension.  I integrated
>that into the text I wrote on that earlier.  I hope somebody out there
>finds this of interest.


Thank you very much for your explanations, Sam.  I gather (though I haven't
read your last message through yet) that programming by extension is
essentially the mechanics part of OOP, without the data and methods
organization part (which I gather is best expressed in Ada using the package
concept).  I hope I've got that right, since I feel like I've had a major
"oh yeah!" breakthrough.  I never thought of separating the two parts
before, although seeing it written out like that I recognize that I've done
forms of the latter organizing in my non-OO programming.







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

* Re: (shorter and new) programming by extension
  1999-02-24  0:00             ` (long) programming by extension Samuel Mize
@ 1999-02-25  0:00               ` Samuel Mize
  1999-02-25  0:00                 ` Mike Silva
  0 siblings, 1 reply; 34+ messages in thread
From: Samuel Mize @ 1999-02-25  0:00 UTC (permalink / raw)


I'm too pedantic to leave adequate-enough alone, so I've refined my
example of non-object-oriented programming by extension.  I integrated
that into the text I wrote on that earlier.  I hope somebody out there
finds this of interest.

Sam Mize
- - - - - - - - - -
Programming by Extension means programming a large system so that new
processing cases can be handled by adding new code, without having to
recode any existing modules.  Language support is extremely helpful
for true programming by extension.

Object-oriented development is a very specific way of analyzing,
designing and coding a system.  It provides a way to program by
extension -- that's one of its selling points -- but it brings along
a lot of other baggage too.

Sometimes you want that baggage.  That's why "object-oriented"
technology exists.  But sometimes you just want to do plain functional
programming, and be able to extend the system later without having to
recode the existing part.  Ada supports this also.

The Ada 95 Rationale describes how Ada supports programming by
extension, but it doesn't really define the term.  Here's a concrete
example of programming by extension.

Consider a function to read up to 20 messages from some interface,
compute statistics and generate a summary.  The rest of the system
only cares about the summary; it doesn't care about the input
messages, or about how the interfaces work.  One simple approach would
put the summarizer function in a separate package, with an enumeration
variable to tell it which interface to use:

   package Simple_Approach is
      type Interfaces is (Disk_File, Serial_Interface, ...);

      type Summary_Type is
         record
            ...
         end record;

      function Summarizer (Interface_To_Use: Interfaces)
         return Summary_Type;

   end Simple_Approach;

The problem, of course, is that adding a new interface will cause
recoding of the type Interfaces and the function Summarizer, and
recompilation of anything that "withs" package Simple_Approach.

Note that Ada is often used in life-critical systems like avionics,
where each unit goes through a long and expensive validation of the
compiled object code.  This must be redone if the unit is recompiled,
even if the source code is not changed.

Lets use programming by extension to prevent all this recoding and
recompilation.  The first question is, what needs to be extended?
In this case, the operation of getting a message from an interface.
So, we'll create a procedure Get that gets a message from an
interface, basing it on a tagged type so it's polymorphic:

   with Message;
   package Generic_Interface is

      type Flag is tagged null record;

      procedure Get (Which_Interface: Flag;
                     Data: Message.Data_Type);

   end Generic_Interface;

We can now write Summarizer as a class-wide procedure, which uses
dispatching to get messages from whatever interface is appropriate:

   with Generic_Interface;
   package Extension_Approach is

      function Summarizer
         (Interface_To_Use: Generic_Interface.Flag'Class)
         return Summary_Type;

   end Extension_Approach;
   - - - - - -
   with Messages;
   package body Extension_Approach is

      function Summarizer
         (Interface_To_Use: Generic_Interface.Flag'Class)
         return Summary_Type
      is
         Data: array (1..20) of Message.Data_Type;
      begin
         for I in 1 .. 20 loop
            Get (Interface_To_Use, Data (I));
            exit when Data (I).Last_Message;
         end loop;
         ...

The body of Get in the package Generic_Interface may return an
exception, or get messages from a default interface (in which case
the package should probably be named Default_Interface).

To extend Summarizer to get messages from a new interface, we just
extend the type Generic_Interface.Flag, and override its Get:

   with Message;
   with Generic_Interface;
   package Disk_Interface is

      type Flag is new Generic_Interface.Flag with null record;

      procedure Get (Which_Interface: Flag;
                     Data: Message.Data_Type);

   end Disk_Interface;

In no case will the type Flag contain any data.

Now we can call Summarizer to get messages from disk and return us
the summary:

    Summary
        := Extension_Approach.Summarizer
            (Disk_Interface.Flag'(null record));

Even if Disk_Interface was written after Summarizer, we don't need to
recompile Summarizer.

With a bit more care we can code almost all the user system so that it
won't need to be recoded, or even recompiled, to handle any new
interface. First we add a declaration to Generic_Interface that lets
the user store a flag variable:

      type Interface_Selector is access constant Flag'Class;
   end Generic_Interface;

In each interface package, we put a constant Selected, so the user
won't have to use the rather clunky syntax "TYPENAME'(null record)".
We also put an access constant that denotes Selected, which can be
stored in a variable of type Interface_Selector.

      Selected: constant Flag := Flag'(null record);

      Selection: constant Generic_Interface.Interface_Selector
         := Selected'Access;

   end Disk_Interface;

(These additions to the _Interface packages are just convenience
items, the user code could make these declarations itself.)

Now, to hard-code which interface is being used, the code can say:

   with Disk_Interface;
   with Extension_Approach; use Extension_Approach;

   procedure User is
      Sum: Summary_Type;
   begin
      Sum := Summarizer (Disk_Interface.Selected);

To encapsulate the knowledge about interfaces in a single package,
the code might look like:

   package Interfaces is
      Current: Generic_Interface.Interface_Selector;
   end Interfaces;
   - - - - -
   with Interfaces;
   with Extension_Approach; use Extension_Approach;
   procedure User is
      Sum: Summary_Type;
   begin
      Sum := Summarizer (Interfaces.Current);
   ...

Now, to extend User, we only have to add another class, and somewhere
there will be a bit of code -- possibly buried in the user interface
-- that we will have to change so it can set Interfaces.Current to
New_Interface.Selection.

The entire rest of the system won't have to be recoded, or even
recompiled.

Another feature of the Programming-by-Extension facilities in Ada 95
is that, when you derive a new type from a tagged type, you can re-use
the "parent" type's procedures, if they still apply.  For example,
suppose that some interfaces must be explicity started and stopped.
The code might look like:

   with Message;
   package Generic_Interface is
      type Flag is tagged null record;

      procedure Get (Which_Interface: Flag;
                     Data: Message.Data_Type);

      procedure Start (Which_Interface: Flag); -- does nothing
      procedure Stop (Which_Interface: Flag); -- does nothing
      ...

   - - - - - -
   with Message;
   package Disk_Interface is
      type Flag is new Generic_Interface.Flag with null record;

      procedure Get (Which_Interface: Flag;
                     Data: Message.Data_Type);

      -- we don't need to start or stop a disk, so the do-nothing Start
      -- inherited from Generic_Interface is just fine
      ...

   - - - - - -
   with Message;
   package Serial_Interface is
      type Flag is new Generic_Interface.Flag with null record;

      procedure Get (Which_Interface: Flag;
                     Data: Message.Data_Type);

      -- Start and stop the serial interface
      procedure Start (Which_Interface: Flag);
      procedure Stop (Which_Interface: Flag);
      ...

And the user code would look like:

   with Interfaces;
   with Extension_Approach; use Extension_Approach;
   procedure User is
      Sum: Summary_Type;
   begin
      Start (Interfaces.Current);
      Sum := Summarizer (Interfaces.Current);
      Stop (Interfaces.Current);
   ...

I hope you find this extended sketch useful.

I would certainly NOT call this object-oriented programming.  But it
does take advantage of the Ada 95 facilities for programming by
extension.  It's sort of an "infinite case statement."  

Certainly this is a contrived example.  I HAVE used tagged types to
generate such an "infinite case statement," but it was buried in an
obscure and proprietary system, so it would be neither clear nor legal
for me to reproduce the code.

You can do the same general things in C++, but you have to make the
window type a class, and each new window type a subclass of that
class.  An instance of the class is an "object."  The terms "class"
and "object" carry a lot of connotations that may not be true in all
cases, for instance that the item in question is a discrete entity
that exists in its own right, or that the "classes" involved form a
meaningful taxonomy and not just a hierarchy that reflects some
implementation concern.

Further, I believe there may be extra semantic constraints and extra
coding effort in using C++ for non-object-oriented programming by
extension.  However, I am not familiar enough with the language to
give you specific details.

Sam Mize

--
Samuel Mize -- smize@imagin.net (home email) -- Team Ada
Fight Spam: see http://www.cauce.org/ \\\ Smert Spamonam




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

* Re: (shorter and new) programming by extension
  1999-02-25  0:00                 ` Mike Silva
@ 1999-02-26  0:00                   ` Samuel Mize
  0 siblings, 0 replies; 34+ messages in thread
From: Samuel Mize @ 1999-02-26  0:00 UTC (permalink / raw)


Mike Silva <mjsilva@jps.net> wrote:
> 
> Samuel Mize wrote in message <7b49mm$t7q@news1.newsguy.com>...
>>I'm too pedantic to leave adequate-enough alone, so I've refined my
>>example of non-object-oriented programming by extension.  I integrated
>>that into the text I wrote on that earlier.  I hope somebody out there
>>finds this of interest.
> 
> 
> Thank you very much for your explanations, Sam.  I gather (though I haven't
> read your last message through yet) that programming by extension is
> essentially the mechanics part of OOP, without the data and methods
> organization part (which I gather is best expressed in Ada using the package
> concept).  I hope I've got that right, since I feel like I've had a major
> "oh yeah!" breakthrough.


Well, your new insight is probably pointed in the right direction,
but I can't agree with your phrasing.  For an initial insight, though,
you're doing very well.

> programming by extension is
> essentially the mechanics part of OOP, without the data and methods
> organization part

In a larger sense, it's any technology that lets you extend the
capabilities of a system by linking in new code, without having to
go in and recode or recompile the existing stuff to integrate it in.

The specific examples I've show use Ada 95's polymorphic subprograms
to do this.

Polymorphism is one mechanism that goes into OOP.  But it isn't ALL of
the "mechanics part of OOP," and it isn't the only possible approach
to "programming by extension."

For instance, many Lisp environments take an extremely flexible view of
function definition and linkage, and it's normal to build up a program
piecemeal.  Many of the techniques used in that kind of "rapid
prototyping" can be legitimately called "programming by extension."

Object-oriented folks like to say that the three touchstones of OO
methods are: abstraction, encapsulation, and inheritance.  I think
it's fair to say that they are talking about abstraction in terms
of objects; functional abstractions, or data-flow abstractions,
aren't object-oriented.

- The non-object-oriented programming by extension that I demonstrated
  uses a purely functional kind of abstraction.

- It doesn't require any encapsulation of data -- all the records may
  well be publicly visible, and changed arbitrarily by any part of the
  rest of the system.

- While inheritance of functions is used, there is no general inheritance
  of data structures.

So, it fails all three mechanical tests for object-orientation.

Furthermore, there is no attempt to create a hierarchy of classes that
define the essential abstractions that organize the system.  This is
the philosophical heart of object-oriented methods.

> the mechanics part of OOP, without the data and methods
> organization part (which I gather is best expressed in Ada using the package
> concept).

Well, I'd identify two issues here:

- encapsulation (preventing anything but the object's methods from
  operating on its data)

- organization (pulling together all and only the stuff related to the
  class, for clarity)

For any type, not just tagged types, encapsulation is enforced with
the package mechanism, but ONLY if you make the type private.  So
it's really an interaction between typing and packaging.

Organization may use packaging, as well as the ordering of the code,
naming conventions, and so on.

Now, if you want to get a "class" in the style of C++, you will want
to define a package that contains only the tagged type with its
operations and support items (like constants).

But you should be aware that this is only one kind of object-oriented
coding.  Ada supports a number of other paradigms.  Some people will
argue violently, even rudely, that that is a very poor kind of
object-oriented technology.

Because Ada 95 only provides the building blocks, you can do whatever
kind of object-oriented development you want.  And, you can do other
things with those building blocks (like non-object-oriented programming
by extension).

Best,
Sam Mize

-- 
Samuel Mize -- smize@imagin.net (home email) -- Team Ada
Fight Spam: see http://www.cauce.org/ \\\ Smert Spamonam




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

end of thread, other threads:[~1999-02-26  0:00 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-02-05  0:00 How to write TYPECASE in Ada 95? Norman Ramsey
1999-02-05  0:00 ` Brian Rogoff
1999-02-05  0:00   ` David C. Hoos, Sr.
1999-02-05  0:00     ` Brian Rogoff
1999-02-06  0:00   ` Ed Falis
1999-02-06  0:00     ` Nick Roberts
1999-02-06  0:00       ` Nick Roberts
1999-02-17  0:00     ` Tom Moran
1999-02-18  0:00       ` Matthew Heaney
1999-02-18  0:00         ` Tom Moran
1999-02-18  0:00         ` robert_dewar
1999-02-19  0:00           ` Nick Roberts
1999-02-19  0:00           ` Tom Moran
1999-02-18  0:00         ` Tom Moran
1999-02-18  0:00           ` Matthew Heaney
1999-02-19  0:00     ` Tom Moran
1999-02-19  0:00       ` Tom Moran
1999-02-23  0:00       ` Samuel Mize
1999-02-23  0:00         ` Question (was Re: How to write TYPECASE in Ada 95?) Mike Silva
1999-02-24  0:00           ` (long) programming by extension (was: " Samuel Mize
1999-02-24  0:00             ` (long) programming by extension Samuel Mize
1999-02-25  0:00               ` (shorter and new) " Samuel Mize
1999-02-25  0:00                 ` Mike Silva
1999-02-26  0:00                   ` Samuel Mize
1999-02-24  0:00           ` Question (was Re: How to write TYPECASE in Ada 95?) Nick Roberts
1999-02-24  0:00           ` Samuel T. Harris
1999-02-24  0:00             ` Matthew Heaney
1999-02-24  0:00               ` Tucker Taft
1999-02-06  0:00 ` How to write TYPECASE in Ada 95? David C. Hoos, Sr.
1999-02-06  0:00   ` Matthew Heaney
1999-02-06  0:00     ` Matthew Heaney
1999-02-06  0:00     ` Matthew Heaney
1999-02-09  0:00     ` David C. Hoos, Sr.
1999-02-06  0:00 ` Matthew Heaney

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