LogoThe Eiffel Compiler / Interpreter (tecomp)

doc/papers/lang/catcall comparable

Discussion of the catcall problem with COMPARABLE

A proposal named "The world is covariant. Is it safe?" to resolve catcall issues has been posted on the Eiffel Software mailing list. At first reading it seems to be sound. However: Does it compromise the Eiffel language too much?

Some issues are discussed below.

The class COMPARABLE has some issues related to catcalls.


It is assumed for the following discussion, that COMPARABLE is defined like

deferred class COMPARABLE feature
	is_less alias "<" convert (other: like Current): BOOLEAN
	is_less_equal alias "<=" convert (other: like Current): BOOLEAN
			Result := Current ~ other or else Current < other
	is_greater alias ">" convert (other: like Current): BOOLEAN
			Result := other < Current

and that the basic numeric classes like INTEGER, REAL etc. inherit from COMPARABLE.


Issue 1

	  a := 1
	  b := 2.0
	  if 2.0 > 1 then
	     -- ok, because INTEGER converts to real, so
             -- (|2.0|).is_greater( {REAL}[1] ) will be called
          elseif 1 < 2.0 then
             -- ok, target conversion applies, because REAL is not 
	     -- compatible with INTEGER and target conversion from
	     -- INTEGER to REAL results in a valid call, i.e.
	     -- {REAL}[1].is_less(2.0) will be called
	  elseif a < b then
	     -- catcall
	  elseif b > a then
	     -- catcall

The above proposal (with frozen and variant types) would make the calls a<b and b>a invalid, because they are not valid for any descendant of COMPARABLE.

So the proposal would allow polymorphic attachments to entities of type comparable but disallow calling any features of comparable. The above catcalls are not valid Eiffel code.

Conclusion: Issue 1 is resolved with the proposal.

Issue 2

The problem can be buried in generic types, e.g.

      extend ( e: G )  do ... end
          create a ....
	  a.extend ( 2.0 )
	  a.extend ( 1 )   -- internally, comparisons between 1 and 2.0 has to
       	  	       	   -- be called => catcall

In the above proposal, the class SORTED_SEQUENCE would not compile, because internally it has to call comparison features <, <=, etc. on entities of type COMPARABLE. This would be invalid, because they are not valid for any combination of COMPARABLEs.

Conclusion: A sorted sequence is not possible any longer or in general, a formal generic G->COMPARABLE is not useful any longer. The solution cuts off meaningful classes. Issue 2 is not resolved.

What is the problem?

The proposed solution still allows polymorphic attachments but it disallows all calls of features with arguments, where the argument type has been covariantly redefined. This is somewhat in conflict with constrained genericity.

Constraint genericity has been invented to allow feature calls on formal generics. The constraints are often behaviour classes like COMPARABLE which have implicit covariance because of arguments anchored to Current. A similar issue arises with NUMERIC.

Therefore constrained genericity will become nearly useless in cases like COMPARABLE if the proposal were implemented.

Proposed solution

There seem to be two facts responsible for the problem:

The first one can be attacked by inheriting form COMPARABLE in a nonconformant manner. This disallows attachments to entities of type COMPARABLE. Attachments to entities of type COMPARABLE are in most cases usesless anyhow. So this might not be a serious limitation.

But another issue arises, because the constraint G->COMPARABLE will become unfulfillable if the actual generic (e.g. INTEGER or REAL) inherits nonconformant from COMPARABLE.

But: Is it really necessary that G->COMPARABLE is tied to conformance? Are there cases, there conformance is important? My first thinking and checking of already existing generic classes having this type of constraint says no.

So why base G->COMPARABLE on conformance? Why not on simple .... inheritance? I.e. base the definition of constraint to a weaker concept.

The reason for having a constraint on a generic is usually not because conformance is required. Usually just "behavioural conformance" (for picking just a word) is required. The actual generic should "behave" like the constraint, i.e. have the same features and contracts as the constraint.

So the proposal is:



Feel free to comment on that topic at

 Local Variables: 
 mode: outline
 coding: iso-latin-1
 outline-regexp: "=\\(=\\)*"
Table of contents

- Asumptions

- Issues

- Issue 1

- Issue 2

- What is the problem?

- Proposed solution

- Discussion