comp.lang.ada
 help / color / mirror / Atom feed
* premature use of private
@ 1999-08-17  0:00 tmoran
  1999-08-17  0:00 ` David C. Hoos, Sr.
  1999-08-17  0:00 ` Matthew Heaney
  0 siblings, 2 replies; 8+ messages in thread
From: tmoran @ 1999-08-17  0:00 UTC (permalink / raw)


I'm given an existing program that processes Apples with routines like
  function Is_Ripe(X : Apple) return Boolean;
  function Is_Red(X : Apple) return Boolean;
  function Size(X : Apple) return Integer;
and
  type Pile is array(integer range <>) of Apple;
  procedure Sort_By_Size(X : in out Pile);

I now need to add Oranges and Grapefruit and ...
So I tried

  type Fruit is abstract tagged private;
  function Is_Ripe(X : Fruit) return Boolean;
  function Size(X : Fruit) return Integer;

  type Apple is new Fruit with private;
  function Is_Red(X : Apple) return Boolean;

  type Orange is new Fruit with private;
  function Florida(X : Orange) return Boolean;

So far so good.  But I don't want a Pile of mixed Fruit, so,
borrowing from Barnes' on Containers, I tried:

  generic
    type This_Fruit is abstract tagged private;
    type Fruit_Ptr is access all This_Fruit;
  package Sets is
    type Pile is array(integer range <>) of Fruit_Ptr;
    procedure Sort_By_Size(X : in out Pile);
  end Sets;

  type Apple_Ptr is access all Apple;
  package Apples is new Sets(Apple, Apple_Ptr);

But that won't work because Apple is private at this point.

  How should this be done?




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

* Re: premature use of private
  1999-08-17  0:00 premature use of private tmoran
@ 1999-08-17  0:00 ` David C. Hoos, Sr.
  1999-08-17  0:00 ` Matthew Heaney
  1 sibling, 0 replies; 8+ messages in thread
From: David C. Hoos, Sr. @ 1999-08-17  0:00 UTC (permalink / raw)



<tmoran@bix.com> wrote in message
news:In2u3.3680$z6.293053@typhoon-sf.snfc21.pbi.net...
> I'm given an existing program that processes Apples with routines like
>   function Is_Ripe(X : Apple) return Boolean;
>   function Is_Red(X : Apple) return Boolean;
>   function Size(X : Apple) return Integer;
> and
>   type Pile is array(integer range <>) of Apple;
>   procedure Sort_By_Size(X : in out Pile);
>
> I now need to add Oranges and Grapefruit and ...
> So I tried
>
>   type Fruit is abstract tagged private;
>   function Is_Ripe(X : Fruit) return Boolean;
>   function Size(X : Fruit) return Integer;
>
>   type Apple is new Fruit with private;
>   function Is_Red(X : Apple) return Boolean;
>
>   type Orange is new Fruit with private;
>   function Florida(X : Orange) return Boolean;
>
> So far so good.  But I don't want a Pile of mixed Fruit, so,
> borrowing from Barnes' on Containers, I tried:
>
>   generic
>     type This_Fruit is abstract tagged private;
>     type Fruit_Ptr is access all This_Fruit;
>   package Sets is
>     type Pile is array(integer range <>) of Fruit_Ptr;
>     procedure Sort_By_Size(X : in out Pile);
>   end Sets;
>
>   type Apple_Ptr is access all Apple;
>   package Apples is new Sets(Apple, Apple_Ptr);
>
> But that won't work because Apple is private at this point.
>
>   How should this be done?

A generic instantiation can be declared (at least with GNAT)
only at a point where the body(ies) of the actual type(s)
with which it is instantiated are available;

Further, it seems to me that to provide for new extensions
without alteration of existing source files, the derived types
should be in their own packages.

Third, it seems that Size and Is_Ripe are intended to be class-wide
functions, and should therefore have formal parameters of Fruit'Class;
Alternatively, if they are not class-wide, they should be declared
abstract so as to require overriding in any type derived from Fruit.

Fourth, based on the English meaning of the identifiers, it doesn't
seem that Sort_By_Size would need to be generic, nor that other
operations on sets of fruit would need (nor could be) specialized
for (as yet) undefined derived types, but perhaps the real abstraction
is different.

Having said all that, here's a skeleton of how I would approach it,
not knowing any more about the abstraction.

package Fruit is

   type Fruit is abstract tagged private;

   function Is_Ripe (X : Fruit'Class) return Boolean;
   function Size (X : Fruit'Class) return Positive;

   generic
      type This_Fruit is new Fruit with private;
      type Fruit_Ptr is access all This_Fruit;
   package Sets is
      type Pile is array (Positive range <>) of Fruit_Ptr;
      procedure Sort_By_Size (X : in out Pile);
   end Sets;

private
   type Fruit is tagged record
      Ripe : Boolean;
      Size : Positive;
   end record;
end Fruit;

package Fruit.Apples is

   type Apple is new Fruit with private;
   function Is_Red (X : Apple) return Boolean;

   type Color is (Green, Red, Yellow);
private

   type Apple is new Fruit with record
      Col : Color;
   end record;
end Fruit.Apples;

package Fruit.Oranges is
   type Orange is new Fruit with private;
   function Florida (X : Orange) return Boolean;
   type Origin is (California, Florida);
private
   type Orange is new Fruit with record
     Orig : Origin;
   end record;
end Fruit.Oranges;

with Fruit.Apples;
with Fruit.Oranges;
procedure Do_Things_With_Fruit is
   type Apple_Ptr is access all Fruit.Apples.Apple;
   package Apples is new Fruit.Sets (Fruit.Apples.Apple, Apple_Ptr);
begin
   null;
end Do_Things_With_Fruit;






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

* Re: premature use of private
  1999-08-17  0:00 premature use of private tmoran
  1999-08-17  0:00 ` David C. Hoos, Sr.
@ 1999-08-17  0:00 ` Matthew Heaney
  1999-08-17  0:00   ` tmoran
  1 sibling, 1 reply; 8+ messages in thread
From: Matthew Heaney @ 1999-08-17  0:00 UTC (permalink / raw)


In article <In2u3.3680$z6.293053@typhoon-sf.snfc21.pbi.net> , tmoran@bix.com
wrote:

> So far so good.  But I don't want a Pile of mixed Fruit, so,
> borrowing from Barnes' on Containers, I tried:
>
>   generic
>     type This_Fruit is abstract tagged private;
>     type Fruit_Ptr is access all This_Fruit;
>   package Sets is
>     type Pile is array(integer range <>) of Fruit_Ptr;
>     procedure Sort_By_Size(X : in out Pile);
>   end Sets;
>
>   type Apple_Ptr is access all Apple;
>   package Apples is new Sets(Apple, Apple_Ptr);
>
> But that won't work because Apple is private at this point.
>
>   How should this be done?

In order to instantiate the package, you need the full view of the type.

I would declare the instantiations as children of the package in which the
type is declared, e.g.:

  package Fruit is

    type Fruit_Type is ...;

    type Apple_Type is new Fruit_Type with private;
    type Apple_Ptr is access all Apple_Type;
...
  end Fruit;

   generic
     type This_Fruit is abstract tagged private;

--or type This_Fruit is new Fruit_Type with private;

     type Fruit_Ptr is access all This_Fruit;

--or, rather than importing the access type as a generic formal type,
--just declare it locally, in the spec of Sets.

   package Fruit.Sets is
     type Pile is array(integer range <>) of Fruit_Ptr;
     procedure Sort_By_Size(X : in out Pile);
   end Fruit.Sets;


Now, for the instantiation:

  with Fruit.Sets;
  package Fruit.Apple_Sets is
    new Fruit_Sets (Apple_Type, Apple_Ptr);

If you go with the child package idea (suggested by David Hoos), then you
structure the hierarchy as:

  package Fruit is

    type Fruit_Type is abstract tagged private;
...
  end Fruit;

  package Fruit.Apples is

    type Apple_Type is new Fruit_Type with private;
    type Apple_Ptr is access all Apple_Type;  -- or Apple_Type'Class
...
  end Fruit.Apples;

  with Fruit.Sets;
  package Fruit.Apples.Sets is
    new Fruit.Sets (Apple_Type, Apple_Ptr);


You don't have to cram the entire world in one package -- break it up into a
package hierarchy.  The idea is to always submit as little program text to
the compiler as possible.

--
Matt

It is impossible to feel great confidence in a negative theory which has
always rested its main support on the weak points of its opponent.

Joseph Needham, "A Mechanistic Criticism of Vitalism"




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

* Re: premature use of private
  1999-08-17  0:00 ` Matthew Heaney
@ 1999-08-17  0:00   ` tmoran
  1999-08-17  0:00     ` David C. Hoos, Sr.
  1999-08-18  0:00     ` Matthew Heaney
  0 siblings, 2 replies; 8+ messages in thread
From: tmoran @ 1999-08-17  0:00 UTC (permalink / raw)


> package Fruit.Apple_Sets is
>   new Fruit_Sets (Apple_Type, Apple_Ptr);
  The fruit stand operator wants a pretty display, so he needs
    function Prettier_Than(X : Fruit_Type) return Fruit.Apple_Sets.Pile;
    function Prettier_Than(X : Fruit_Type) return Fruit.Orange_Sets.Pile;
    etc.
for those occasions when he wants to display a nice apple surrounded
by even prettier oranges from his stock, or whatever.  Does he need
  with Fruit, Fruit.Apple_Sets, Fruit.Orange_Sets;
package Getting_Complicated is
  function Prettier_Than(X : Fruit_Type) return Fruit.Apple_Sets.Pile;
  function Prettier_Than(X : Fruit_Type) return Fruit.Orange_Sets.Pile;
  ...
It seems unreasonable that it should be so much trouble just to
declare a simple *homogenous* array.  I understand that the compiler
has a probem with an array when it doesn't yet know the size of its
elements, but here the elements are all pointers, so that isn't
a problem.




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

* Re: premature use of private
  1999-08-17  0:00   ` tmoran
@ 1999-08-17  0:00     ` David C. Hoos, Sr.
  1999-08-18  0:00     ` Matthew Heaney
  1 sibling, 0 replies; 8+ messages in thread
From: David C. Hoos, Sr. @ 1999-08-17  0:00 UTC (permalink / raw)



<tmoran@bix.com> wrote in message
news:Lgju3.398$06.54131@typhoon-sf.snfc21.pbi.net...
> > package Fruit.Apple_Sets is
> >   new Fruit_Sets (Apple_Type, Apple_Ptr);
>   The fruit stand operator wants a pretty display, so he needs
>     function Prettier_Than(X : Fruit_Type) return Fruit.Apple_Sets.Pile;
>     function Prettier_Than(X : Fruit_Type) return Fruit.Orange_Sets.Pile;
>     etc.
> for those occasions when he wants to display a nice apple surrounded
> by even prettier oranges from his stock, or whatever.  Does he need
>   with Fruit, Fruit.Apple_Sets, Fruit.Orange_Sets;

No.  mentioning a child pacage in a context clause gives visibility to
the child and all of its ancestors.

> package Getting_Complicated is
>   function Prettier_Than(X : Fruit_Type) return Fruit.Apple_Sets.Pile;
>   function Prettier_Than(X : Fruit_Type) return Fruit.Orange_Sets.Pile;
>   ...
> It seems unreasonable that it should be so much trouble just to
> declare a simple *homogenous* array.  I understand that the compiler
> has a probem with an array when it doesn't yet know the size of its
> elements, but here the elements are all pointers, so that isn't
> a problem.

Have you forgotten that your Set package is more than just a "homogeneous"
array of pointers?  You've declared an operation Sort_By_Size which implies
dereferencing those pointers and performing operations on the object
itself.





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

* Re: premature use of private
  1999-08-17  0:00   ` tmoran
  1999-08-17  0:00     ` David C. Hoos, Sr.
@ 1999-08-18  0:00     ` Matthew Heaney
  1999-08-18  0:00       ` tmoran
  1 sibling, 1 reply; 8+ messages in thread
From: Matthew Heaney @ 1999-08-18  0:00 UTC (permalink / raw)


In article <Lgju3.398$06.54131@typhoon-sf.snfc21.pbi.net> , tmoran@bix.com
wrote:


> with Fruit, Fruit.Apple_Sets, Fruit.Orange_Sets;

The statement

  with Fruit.Apple_Sets, Fruit.Orange_Sets;

will do.

> package Getting_Complicated is
>   function Prettier_Than(X : Fruit_Type) return Fruit.Apple_Sets.Pile;
>   function Prettier_Than(X : Fruit_Type) return Fruit.Orange_Sets.Pile;
>   ...
> It seems unreasonable that it should be so much trouble just to
> declare a simple *homogenous* array.

Then perhaps you overcommitted.  Your access type is a pointer to a specific
kind of fruit (Apple_Ptr, Orange_Ptr, etc).  This gives you a static
guarantee about the specific type designated by the access object.

If you don't need that much to be known statically, then you can loosen up
the types by simply using an access type that designates Fruit_Type'Class.
You wouldn't even need the generic anymore.  You make the rule
("precondition") that it's up to the client to make sure that the array is
populated by only one type.

> I understand that the compiler has a probem with an array when it doesn't yet
> know the size of its elements, but here the elements are all pointers, so that
> isn't a problem.

Then just make an array of

  type Fruit_Access is access all Fruit_Type'Class;
  type Fruit_Array is array (Positive range <>) of Fruit_Access;

You can then write functions like:

  function Apples_Prettier_Than
    (X : Fruit_Type) return Fruit_Array;

with a postcondition that all components of the return value are of specific
type Apple_Type; and

  function Oranges_Prettier_Than
    (X : Fruit_Type) return Fruit_Array;

with a postcondition that all components of the return value are of specific
type Orange_Type.

Remember that not all constraints have to be satisfied statically by the
compiler (by using pointers to specific types).  Use pointers to the
class-wide root, and specify pre- and post- conditions about the nature of
the actual specific type designated.

--
Matt

It is impossible to feel great confidence in a negative theory which has
always rested its main support on the weak points of its opponent.

Joseph Needham, "A Mechanistic Criticism of Vitalism"




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

* Re: premature use of private
  1999-08-18  0:00     ` Matthew Heaney
@ 1999-08-18  0:00       ` tmoran
  1999-08-18  0:00         ` Matthew Heaney
  0 siblings, 1 reply; 8+ messages in thread
From: tmoran @ 1999-08-18  0:00 UTC (permalink / raw)


>If you don't need that much to be known statically, then you can loosen up
>the types by simply using an access type that designates Fruit_Type'Class.
>You wouldn't even need the generic anymore.  You make the rule
>("precondition") that it's up to the client to make sure that the array is
>populated by only one type.
  Exactly what I want to avoid.  The whole intent was to get the
compiler to statically check that the array is homogenous.  It is,
I gather, not possible to do this and to make generic subprograms
that operate on such a homogenous array - but homogeneous on
different types.  So either I can use the generic, but it will need
to dynamically check homogeneity, or I can not use a generic, but
instead re-copy the relevant code, once for Apple_Set, once for
Orange_Set, etc.  One is ugly and wasteful at run time, the other
is ugly and wasteful at compile time.




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

* Re: premature use of private
  1999-08-18  0:00       ` tmoran
@ 1999-08-18  0:00         ` Matthew Heaney
  0 siblings, 0 replies; 8+ messages in thread
From: Matthew Heaney @ 1999-08-18  0:00 UTC (permalink / raw)


In article <0ZCu3.300$26.56649@typhoon-sf.snfc21.pbi.net> , tmoran@bix.com
wrote:

> The whole intent was to get the compiler to statically check that the array is
> homogenous.  It is, I gather, not possible to do this and to make generic
> subprograms that operate on such a homogenous array - but homogeneous on
> different types.

I woudn't say that.  How about if we keep your generic set package, but make
Better_Than a generic too:

  generic
  procedure Fruit.Sets.Better_Than_G
    (This_Fruit : Fruit_Type) return Pile;
    -- (Not sure if Pile needs expanded name)

Now you can just create another child of your set instantiations:

  with Fruit.Sets.Better_Than_G;
  procedure Fruit.Apple_Sets.Better_Than is
    new Fruit.Apple_Sets.Better_Than_G;


  with Fruit.Sets.Better_Than_G;
  procedure Fruit.Orange_Sets.Better_Than is
    new Fruit.Orange_Sets.Better_Than_G;


> So either I can use the generic, but it will need to dynamically check
> homogeneity,

No -- you're missing the point of a "precondition."  It is NOT up to you the
supplier to make sure that an array is really homogeneneous; that is the
client's responsibility.

If the client fails to satisfy the precondition, then it's his problem.

> or I can not use a generic, but instead re-copy the relevant
> code, once for Apple_Set, once for Orange_Set, etc.

No -- you can use a generic.  The generic function can be a child of the
generic set package (as illustrated above), or,  you can make it a sibling
that imports the instantiation as a generic formal package:

  with Fruit.Sets;  -- a better name would be "Fruit.Sets_G"
  generic
    with package Fruit_Sets is new Fruit.Sets (<>);  -- need actual params?
  function Fruit.Better_Than_G
    (This_Fruit : Fruit_Type) return Fruit_Sets.Pile;


> One is ugly and wasteful at run time, the other is ugly and wasteful at
> compile time.

It is only wasteful at run-time if you explicitly check the precondition.

If you want to do so during development, I won't argue too much.  But I
don't agree that a supplier should always check -- especially in a delivered
system -- the preconditions that are up to the client to satisfy.  Stop
mistrusting the client.

Read Meyer's OOSC (either ed.) for the best explication of this topic.

And yes, a generic Better_Than is possible, so there's no ugliness at
compile-time either.
--
Matt

It is impossible to feel great confidence in a negative theory which has
always rested its main support on the weak points of its opponent.

Joseph Needham, "A Mechanistic Criticism of Vitalism"




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

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

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-08-17  0:00 premature use of private tmoran
1999-08-17  0:00 ` David C. Hoos, Sr.
1999-08-17  0:00 ` Matthew Heaney
1999-08-17  0:00   ` tmoran
1999-08-17  0:00     ` David C. Hoos, Sr.
1999-08-18  0:00     ` Matthew Heaney
1999-08-18  0:00       ` tmoran
1999-08-18  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