[comp.lang.eiffel] parameterized class types as parameters

jwg1@bunny.gte.com (James W. Gish) (04/27/89)

I have come across the following problem with parameterized classes.  I would
appreciate any comments you might have on the problem or its resolution.

Suppose I have three tables declared in my root class:
   term_table: H_TABLE[ TERM ];
   attribute_table: H_TABLE[ ATTRIBUTE ];
   cluster_table: H_TABLE[ CLUSTER ];

I want to have a routine that prompts the user for a unique name:

   get_unique_name( table: H_TABLE ): STRING is
      local
         is_unique : BOOLEAN
      do
         from is_unique := FALSE
         until is_unique
         do
--          prompt for the name
            Result := prompt_for_name(...);
--          check for uniqueness in the specified table
            is_unique := not table.present( Result );
         end;
      end;

And I want to be able to get names for TERMs, ATTRIBUTEs, and CLUSTERs that
are unique w.r.t. the corresponding tables:

      unique_term_name, unique_cluster_name, unique_attr_name: STRING;

      unique_term_name        := get_unique_name( term_table );
      unique_attribute_name   := get_unique_name( attribute_table );
      unique_cluster_name     := get_unique_name( cluster_table );

The compiler does not complain about the formal argument from the routine 
declaration:
   get_unique_name( table: H_TABLE ) ...

However, it does complain about the following:
   is_unique := not table.present( Result );

with the error message:
   "Incorrect number of actual generic parameters for class h_table"

In general, I see the problem here.  You need to fix the actual
parameter of H_TABLE so that you don't attempt to invoke features of
table entries that don't exist. For example, if TERM had a feature foo
and ATTRIBUTE did not, you want to avoid calling 
   table.element( "KEY").foo

However, in the cases where the compiler can figure out that reference
to the elements of H_TABLE are not being made, this is overly
restrictive.

The solution I came up with is ugly, but the only one I could figure out
given the current language definition:

Define 
   class TABLE
   end; -- TABLE

and inherit TABLE in TERM, ATTRIBUTE and CLUSTER.
Then the declaration of get_unique_name becomes:

   get_unique_name( table: H_TABLE[ TABLE ] ): STRING is ...

This works fine but I shouldn't have to muck with TERM, ATTRIBUTE, and
CLUSTER to accomplish this.  It really violates information hiding
principles and inhibits reusability.

What I would like, is for the compiler to figure out which cases are
legal.

In the absence of that, I propose a form of constrained parameterization.
For example,
   get_unique_name( table: H_TABLE[->TERM;CLUSTER;ATTRIBUTE] ): STRING ...

This says that the actual parameter corresponding to table must be one of
   H_TABLE[TERM], H_TABLE[CLUSTER] or H_TABLE[ATTRIBUTE].  

This would free me from TERM, CLUSTER, and ATTRIBUTE having to know
about TABLE, which they SHOULDN'T know about. It would also allow the
compiler to check for existence of features like foo in the above
example.

Any comments?
--
Jim Gish
GTE Laboratories, Inc., Waltham, MA
CSNET: jgish@gte.com    UUCP:  ..!harvard!bunny!jwg1