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