comp.lang.ada
 help / color / mirror / Atom feed
From: John Volan <johnv@ac3i.dseg.ti.com>
Subject: Re: Mutually dependent private types
Date: 1998/05/26
Date: 1998-05-26T00:00:00+00:00	[thread overview]
Message-ID: <356B6D65.BD34E3EF@ac3i.dseg.ti.com> (raw)
In-Reply-To: EACHUS.98May26090217@spectre.mitre.org


Robert I. Eachus wrote:
> 
> In article <matthew_heaney-ya023680002205981805440001@news.ni.net> matthew_heaney@acm.org (Matthew Heaney) writes:
> 
>  > Furthermore, this split is only required when there's mutual dependency.
>  > Most types are definitely not mutually dependent, and so this workaround
>  > should only seldom be necessary.
> 
>     I would argue, from experience, that every time I have found an
> apparent need for this mutual dependency, it indicates I have not
> fully studied the problem.   For example in John's example of
> employees and offices, it quickly becomes obvious that not all rooms
> are offices, and not all people are employees, so you end up needing
> at least one of the parent classes for other reasons.

Hold on a minute there!  You're falling into the "reality" fallacy:
That's where one relies too heavily on philosophical (and supposedly
"objective") knowledge about "real-world" objects to guide the design of
software objects.  Software objects shouldn't be grab-bags of irrelevant
domain information, they should be encapsulations of the actual
responsibilities of an actual target system.

Suppose I were to tell you that, for a certain target application, the
concepts of "employee" and "office" were entirely sufficient to
encapsulate the responsibilities of that application; and that the
notion of "person" as a generalization for "employee", and "room" as a
generalization for "office", were totally unnecessary and irrelevant. In
other words, that system has lots of functional requirements that apply
to "employees" and "offices" specifically, but absolutely no
requirements that apply to "people" and "rooms" in general. But suppose
we still had an unresolvable mutual dependency between the "employee"
and "office" classes.  Under those circumstances, introducing a
"Person_Type" and deriving "Employee_Type" from it would be specious;
you might as well just have an "Employee_Forward_Type" and derive
"Employee_Type" from that.

But suppose for the sake of argument we consider a somewhat different
target application, one where the "person" and "room" generalizations
are relevant, and we do have some functional requirements that apply to
those generalizations.  For instance, our application is keeping track
of "employees" and "customers", which are both kinds of "persons", and
there's something common that we do for all "persons"; likewise, the
application tracks "offices", "meeting rooms", "restrooms", etc., all as
specializations of "room", and there's something common we do for all
"rooms".  

But let's say we still have other functional requirements that apply to
"employee" and "office" specifically, and among those functional
requirements there's still a mutual dependency between "employee" and
"office".  For instance, let's say we can assign an office to an
employee, for use as that employee's everyday workspace.  For every
office we keep track of the assigned employee, and for every employee,
we keep track of the assigned office.  But an assigned employee has to
be an employee, not just any kind of person -- for instance, you can't
assign an office to a customer. And an assigned office has to be an
office, it can't just be any kind of room -- for instance, you can't put
an employee's desk in a meeting room or a restroom. (Well, you might,
but that employee wouldn't stay an employee for long... :-)

Given the above requirements, the natural thing to do would be to
declare the following packages, but they're unfortunately illegal
because of the mutual spec dependency:

with Persons;
with Offices;
package Employees is
  type Employee_Type is new Persons.Person_Type with private;
  procedure Assign_Office
    (Employee : in out Employee_Type;
     Office   : in out Offices.Office_Type'Class);
  function Get_Assigned_Office (Employee : in Employee_Type)
    return Offices.Office_Type'Class;
  ...
end Employees;

with Rooms;
with Employees;
package Offices is
  type Office_Type is new Rooms.Room_Type with private;
  procedure Assign_Employee
    (Office   : in out Office_Type;
     Employee : in out Employees.Employee_Type'Class);
  function Get_Assigned_Employee (Office : in Office_Type)
    return Employees.Employee_Type'Class;
  ...
end Offices;

The following avoids the mutual spec dependency, but it loses something:

with Persons;
with Rooms;
package Employees is
  type Employee_Type is new Persons.Person_Type with private;
  procedure Assign_Office
    (Employee : in out Employee_Type;
     Office   : in out Rooms.Room_Type'Class);
    -- precondition: Office in Offices.Office_Type'Class
  function Get_Assigned_Office (Employee : in Employee_Type)
    return Rooms.Room_Type'Class;
    -- postcondition: return result in Offices.Office_Type'Class;
  ...
end Employees;

with Rooms;
with Persons;
package Offices is
  type Office_Type is new Rooms.Room_Type with private;
  procedure Assign_Employee
    (Office   : in out Office_Type;
     Employee : in out Persons.Person_Type'Class);
    -- precondition: Employee in Employees.Employee_Type
  function Get_Assigned_Employee (Office : in Office_Type)
    return Persons.Person_Type'Class;
    -- postcondition: return result in Employees.Employee_Type'Class
  ...
end Offices;

You might as well go with an approach a la Norman Cohen:

with Persons;
package Employees_Forward is
  type Employee_Forward_Type is 
    abstract new Persons.Person_Type with null record;
end Employees_Forward;

with Rooms;
package Offices_Forward is
  type Office_Forward_Type is
    abstract new Rooms.Room_Type with null record;
end Offices_Forward;

with Employees_Forward;
with Offices_Forward;
package Employees is
  type Employee_Type is
    new Employees_Forward.Employee_Forward_Type with private;
  procedure Assign_Office
    (Employee : in out Employee_Type;
     Office   : in out Offices_Forward.Office_Forward_Type'Class);
  function Get_Assigned_Office (Employee : in Employee_Type)
    return Offices_Forward.Office_Forward_Type'Class;
  ...
end Employees;

with Offices_Forward;
with Employees_Forward;
package Offices is
  type Office_Type is 
    new Offices_Forward.Office_Forward_Type with private;
  procedure Assign_Employee
    (Office   : in out Office_Type;
     Employee : in out Employees_Forward.Employee_Forward_Type'Class);
  function Get_Assigned_Employee (Office : in Office_Type)
    return Employees_Forward.Employee_Forward_Type'Class;
  ...
end Offices;

>     Note also that once both types have been declared, the needed
> operations with the static checks can be declared, you just have this
> annoying artifact of a visible function which is implicitly required
> to do a static check at run time.  What really is needed is a language
> independent way to "cast away 'CLASS" and move the check from within
> the subprogram to a (required) static type check at the location of
> the call.  This certainly can be done by a pragma.  In fact you would
> think that pragma Restrictions (No_Dispatch) would do precisely that,
> but it is too restrictive, outlawing all cases of 'CLASS.
> 
>     So I suggest that we need a pragma Static_Dispatch which directs
> the compiler to eliminate dispatching tables for the named unit and to
> reject any unit which calls the unit in a way that requires
> dispatching.  Of course, if the unit is called from within any other
> primitive operation of the type, that operation will also require the
> pragma, so maybe a better solution is to have the pragma apply to (all
> the primitive operations of) a type, but not to primitive operations
> of types derived from that type.  Since its indended use is for those,
> usually abstract, parent types in situations like this, the effect
> would be to outlaw dispatching call using Person'Class or Room'Class,
> but allow dispatching on Employee'Class or Office'Class.

This makes no sense to me.  The entire raison d'etre for abstract
classes such as Person and Room would be precisely for polymorphic
dynamic dispatching!  Surely the kind of pragma you suggest should be
applied to "spurious" superclasses that are meant to act merely as
forward type declarations, e.g., Employee_Forward_Type and
Office_Forward_Type.

But then neither of those Forward_Types would have any primitives. The
whole point to the Forward_Types was to defer defining any primitives
for employees or offices until the actual types could be declared.

-- 
Signature volanSignature = 
  new Signature
  ( /*name:      */ "John G. Volan",
    /*employer:  */ "Raytheon Advanced C3I Systems, San Jose",
    /*workEmail: */ "johnv@ac3i.dseg.ti.com",
    /*homeEmail: */ "johnvolan@sprintmail.com",
    /*selfPlug:  */ "Sun Certified Java Programmer",
    /*twoCents:  */ "Java would be even cooler with Ada95's " +
                    "generics, enumerated types, function types, " +
                    "named parameter passing, etc...",
    /*disclaimer:*/ "These views not packaged in COM.ti.dseg.ac3i, " +
                    "so loading them throws DontQuoteMeError. :-)" );




  reply	other threads:[~1998-05-26  0:00 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1998-05-21  0:00 Mutually dependent private types adam
1998-05-21  0:00 ` John Volan
1998-05-21  0:00 ` Matthew Heaney
1998-05-22  0:00   ` John Volan
1998-05-22  0:00     ` Matthew Heaney
1998-05-26  0:00       ` Robert I. Eachus
1998-05-26  0:00         ` John Volan [this message]
1998-05-27  0:00           ` Robert I. Eachus
1998-05-29  0:00             ` John Volan
1998-05-27  0:00           ` Jerry van Dijk
1998-05-29  0:00             ` John Volan
1998-05-26  0:00       ` John Volan
1998-05-26  0:00         ` Matthew Heaney
1998-05-27  0:00           ` John Volan
1998-05-27  0:00             ` Matthew Heaney
1998-05-28  0:00               ` John Volan
1998-05-28  0:00                 ` Matthew Heaney
1998-05-29  0:00                   ` John Volan
1998-05-29  0:00                 ` Brian Rogoff
1998-05-29  0:00                   ` John Volan
1998-05-29  0:00                     ` Brian Rogoff
1998-05-29  0:00                       ` John Volan
1998-05-30  0:00                 ` Geoff Bull
1998-05-30  0:00                   ` Fergus Henderson
1998-06-01  0:00                     ` John Volan
1998-06-02  0:00                       ` Fergus Henderson
1998-06-04  0:00                       ` Robert Dewar
  -- strict thread matches above, loose matches on Subject: below --
1998-05-22  0:00 adam
1998-05-22  0:00 ` Matthew Heaney
1998-05-22  0:00 ` Brian Rogoff
1998-05-22  0:00 ` John Volan
replies disabled

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