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/27
Date: 1998-05-27T00:00:00+00:00	[thread overview]
Message-ID: <356C8A02.44354B09@ac3i.dseg.ti.com> (raw)
In-Reply-To: m3d8d08yk6.fsf@mheaney.ni.net


Matthew Heaney wrote:
> 
> John Volan <johnv@ac3i.dseg.ti.com> writes:
> 
> > Furthermore, what if you're already using inheritance to support true
> > polymorphism, and then you discover you need to break a mutual
> > dependency somewhere in your class hierarchy?  You might end up with a
> > situation I call "inheritance collision": That's where you're trying to
> > apply Ada's inheritance mechanism for two competing purposes, but you're
> > faced with the fact that Ada only supports single inheritance.  Sure,
> > it's possible to wiggle your inheritance hierarchy around so that it'll
> > work and you can still keep your mutually-dependent types in different
> > packages. But I find that to be awkward and artificial.
> 
> If you have deep or otherwise "complex" type hierarchies in Ada, then
> you're doing something wrong.  Hierarchies should be shallow.
> 
> When I hear stories about problems someone is having with their
> inheritance hierarchies, I become suspicious, because it often indicates
> that the programmer is fighting the langauge.

While I wholeheartedly agree with this sentiment, it has little to do
with the situation we have here.  Sure, if an inheritance collision is
caused by a flawed analysis of the problem domain, you should question
the designer's choice of classes.  But here we're talking about
inheritance collision caused by the attempt to apply Ada95's inheritance
mechanism to resolve a mutual dependency *while at the same time* using
it to implement a "legitimate" case of polymorphism -- "legitimate"
because it's motivated by a real case of generalization/specialization
in the problem domain.  This polymorphism hierarchy could be quite
simple and shallow and meet any criterion of "goodness" you can name,
but the mutual dependency could still collide with it.

I believe the example I used in the past was:

    Manager -- supervises -- Employee
    Manager -- is a kind of -- Employee

This is a case where you might have a mutual dependency between a
generalization (Employee) and one of its own specializations (Manager). 
You need Ada95's inheritance mechanism to implement the
generalization/specialization relationship; but this might collide with
resolving the mutual dependency.

Here's our first cut, where we run into the illegal mutual spec
dependency:

with Managers; -- illegal
package Employees is  
  type Employee_Type is abstract tagged limited private;
  type Employee_Access_Type is access all Employee_Type'Class;
  function Get_Supervisor (Employee : in Employee_Type)
    return Managers.Manager_Access_Type;
  ...
end Employees;

with Sets;
with Employees;
package Employee_Sets is
  new Sets (Element => Employees.Employee_Access_Type);

with Employees; -- illegal
package Managers is
  type Manager_Type is new Employees.Employee_Type with private;
  type Manager_Access_Type is access all Manager_Type'Class;
  function Get_Subordinates (Manager : in Manager_Type)
    return Employee_Sets.Set_Type;
  ...
end Managers;

Here's the second cut, where we run into inheritance collision:

package Employees_Forward is
  type Employee_Forward_Type is abstract tagged limited null record;
  type Employee_Access_Type is access all Employee_Forward_Type'Class;
end Employees_Forward;

package Managers_Forward is
  type Manager_Forward_Type is abstract tagged limited null record;
  type Manager_Access_Type is access all Manager_Forward_Type'Class;
end Managers_Forward;

with Employees_Forward;
with Sets;
package Employee_Sets is
  new Sets (Element => Employees_Forward.Employee_Access_Type);

with Employees_Forward;
with Managers_Forward;
package Employees is  
  type Employee_Type is 
    abstract new Employees_Forward.Employee_Forward_Type with private;
  function Get_Supervisor (Employee : in Employee_Type)
    return Managers_Forward.Manager_Access_Type;
  ...
end Employees;

with Managers_Forward;
with Employees;
with Employee_Sets;
package Managers is

  type Manager_Type is 
    -- Need this to resolve the mutual dependency:
    new Managers_Forward.Manager_Forward_Type with private;
    -- But need this to implement the generalization/specialization:
    new Employees.Employee_Type with private;
    -- Inheritance Collision!

  function Get_Subordinates (Manager : in Manager_Type)
    return Employee_Sets.Set_Type;
  ...
end Managers;

To resolve the inheritance collision, we have to do some monkeying
around:

with Employees_Forward;
package Employees is  
  type Employee_Type is 
    abstract new Employees_Forward.Employee_Forward_Type with private;
    -- actually, don't really need Employees_Forward unless there's
    -- a mutual dependency with something else...
  type Employee_Access_Type is access all Employee_Type'Class;

  type Manager_Forward_Type is
    abstract new Employee_Type with private;
  type Manager_Access_Type is access all Manager_Forward_Type'Class;

  function Get_Supervisor (Employee : in Employee_Type)
    return Manager_Access_Type;
  ...
end Employees;

with Employees;
with Employee_Sets;
package Managers is
  type Manager_Type is 
    new Employees.Manager_Forward_Type with private;
  function Get_Subordinates (Manager : in Manager_Type)
    return Employee_Sets.Set_Type;
  ...
end Managers;

Following Norman Cohen's scheme, we had a nice pattern going there with
those *_Forward packages.  But to avoid inheritance collision, we had to
break this pattern and move the Manager_Forward_Type from the
Managers_Forward package into the Employees package.

By rights, forward type declarations ought to be a language feature
that's totally orthogonal to inheritance and polymorphism.  This would
indeed be true in Tucker's "with type" proposal:

with type Managers.Manager_Type;
package Managers_Access is
  type Manager_Access_Type is access all Managers.Manager_Type'Class;
end Managers_Access;

with type Employees.Employee_Type;
package Employees_Access is
  type Employee_Access_Type is access all Employees.Employee_Type'Class;
end Employees_Access;

with Employees_Access;
with Sets;
package Employee_Sets is
  new Sets (Element => Employees_Access.Employee_Access_Type);

with Managers_Access;
package Employees is
  type Employee_Type is abstract tagged limited private;
  function Get_Supervisor (Employee : in Employee_Type)
    return Managers_Access.Manager_Access_Type;
  ...
end Employees;

with Employees;
with Employee_Sets;
package Managers is
  type Manager_Type is new Employees.Employee_Type with private;
  function Get_Subordinates (Manager : in Manager_Type)
    return Employee_Sets.Set_Type;
  ...
end Managers;

As a workaround, my generic Forward package also manages to keep itself
orthogonal to inheritance:

with Forward;
package Employees_Forward is new Forward;

with Forward;
package Managers_Forward is new Forward;

with Employees_Forward;
with Sets;
package Employee_Sets is 
  new Sets (Element => Employees_Forward.Reference_Type);
 
with Employees_Forward;
with Managers_Forward;
package Employees is  
  package Forward renames Employees_Forward;
  type Employee_Type is abstract tagged limited private;
  type Employee_Access_Type is access all Employee_Type'Class;
  function Get_Supervisor (Employee : in Employee_Type)
    return Managers_Forward.Reference_Type;
  ...
end Employees;

with Managers_Forward
with Employees;
with Employee_Sets;
package Managers is
  package Forward renames Managers_Forward;
  type Manager_Type is new Employees.Employee_Type with private;
  type Manager_Access_Type is access all Manager_Type'Class;
  function Get_Subordinates (Manager : in Manager_Type)
    return Employee_Sets.Set_Type;
  ...
end Managers;

package Employees.Binding is
  new Employees.Forward.Binding (Employee_Type, Employee_Access_Type);

package Managers.Binding is
  new Managers.Forward.Binding (Manager_Type, Manager_Access_Type);

But, although you can twist Norman Cohen's technique around so that it
will still work even in the most extreme case, the fact that you have to
do that shows that it isn't a very orthogonal workaround.

-- 
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-27  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 ` 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
1998-05-27  0:00           ` Jerry van Dijk
1998-05-29  0:00             ` John Volan
1998-05-27  0:00           ` Robert I. Eachus
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 [this message]
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
1998-05-21  0:00 ` John Volan
  -- 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