comp.lang.ada
 help / color / mirror / Atom feed
From: eachus@mitre-bedford.arpa  (Robert I. Eachus)
Subject: Re: Mutual distrust
Date: 10 Jul 91 22:06:45 GMT	[thread overview]
Message-ID: <EACHUS.91Jul10150645@largo.mitre.org> (raw)

In article <6883@ns-mx.uiowa.edu> jones@pyrite.cs.uiowa.edu (Douglas W. Jones,2
01H MLH,3193350740,3193382879) writes:

   Here's a problem I've come up against in designing a simulation
   program voluntarily written in Ada...  The problem: Each PLACE must
   have an associated set of people who occupy that PLACE, and each
   PERSON must know what place he (or she) is in and what other people
   occupy that same place.  This implies a cyclic relationship between
   the packages GEOGRAPHY and POPULATION.

   The one simplifying factor is that there is only one place in which it is
   necessary for the PLACE occupied by a PERSON to be known, and that is
   inside the action routines applied to that particular PERSON, which are
   inside POPULATION.

   Here are the possible solutions I thought up:

   1) Add a third package -- something of a relational package that associates
       people with places, so that given a PLACE it can supply the set of all
       people there, and given a PERSON, it can tell what PLACE that person
       occupies.

       This has the advantage of allowing GEOGRAPHY and POPULATION to be
       completely independant, but because PERSON and PLACE are private
       types, there is no way I can think of to efficiently implement this
       third package.

-- There is an easy way to do this using the Tucker Taft amendment,
-- which allows an incomplete type declaration in a private part to be
-- completed in the body of the package...

    package POPULATION is
      type PERSON is private;
      -- operrations on PERSONs not explicitly involving PLACEs.
      ...
    private
      type PERSON_RECORD;
      type PERSON is access PERSON_RECORD;
    end POPULATION;

    package GEOGRAPHY is
      type PLACE is private;
      -- operations on PLACEs not explicitly involving people.
      ...
    private
      type PLACE_RECORD is private;
      type PLACE is access PLACE_RECORD;
    end GEOGRAPHY;

    with POPULATION; with GEOGRAPHY;
    package PEOPLE_AND_PLACES is
      -- operations involving both people and places...
    end PEOPLE_AND_PLACES;

    with POPULATION; with GEOGRAPHY;
    package HIDDEN is
      type REAL_PERSON is record...
      type REAL_PLACE is record...
      function GET_REAL(P: in POPULATION.PERSON) return REAL_PERSON;
      function GET_REAL(P: in GEOGRAPHY.PLACE) return REAL_PLACE;
    end HIDDEN;

    with UNCHECKED_CONVERSION;
    package body HIDDEN is
      type PERSON_POINTER is access REAL_PERSON;
      function CONVERT is new UNCHECKED_CONVERSION
          (POPULATION.PERSON, PERSON_POINTER);

      function GET_REAL(P: in POPULATION.PERSON) return REAL_PERSON is
      begin return CONVERT(P); end GET_REAL;
      -- do the same for PLACEs
      ...
    end HIDDEN;

    with HIDDEN; 
    package body GEOGRAPHY is
      type PLACE_RECORD is new HIDDEN.REAL_PLACE;

--     Now you can see the actual record declarations in POPULATION,
-- GEOGRAPHY, and PEOPLE_AND_PLACES (assuming that these bodies and
-- only these bodies say with HIDDEN.   Revising either of the record
-- structures will require recompiling the bodies of all three
-- packages but you would have to recomile two of them anyway.
-- However, the only specification which requires recompilation is
-- that for HIDDEN. 

--     I usually only advocate packages like HIDDEN as a way of
-- minimizing recompilations, but sometimes it has other advantages.

   2) Take advantage of the simplifying factor, which allows the following
       package dependancy to be established...

       This is the solution I ended up using, but I don't like the assymetry
       of it, and I don't like what I have to do to it to allow OCCUPANT to
       return a set of people instead of a single PERSON.

--       What's the problem? Have two functions one, call it COUNT,
-- returns the number of residents and the other, OCCUPANTS, returns an
-- array of PERSONs.  The loop which processes this may have to use a
-- different trick... Let's say that POPULATION.PEOPLE is an array
-- (POSITIVE range <>) of PERSON.

         loop
           SOMEPLACE := ...
           -- get next location
           declare
             SOMEPEOPLE: constant POPULATION.PEOPLE :=
					 OCCUPANTS(SOMEPLACE); 
           begin
             for I in SOMEPEOPLE'RANGE loop
               PROCESS(SOMEPEOPLE(I));
             end loop;
           end;
         end loop;

--      The constant keyword is the magic cookie which allows you to
-- declare SOMEPEOPLE without supplying the range.  Since PERSON is an
-- access type, PROCESS is allowed to change fields of the various
-- records but not to assign a new access value to SOMEPEOPLE(I).
--

					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...

             reply	other threads:[~1991-07-10 22:06 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1991-07-10 22:06 Robert I. Eachus [this message]
  -- strict thread matches above, loose matches on Subject: below --
1991-07-10 22:17 Mutual distrust cis.ohio-state.edu!magnus.acs.ohio-state.edu!zaphod.mps.ohio-state.edu!ho
replies disabled

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