0

(emphasis mine)

Covariant redefinition of fields and functions provides no problems, but covariant redefinition of arguments does create a problem that illegal types can be passed as arguments.

But, if redefining field and function types covariantly causes no problems, then how come redefining an argument's type covariantly can cause trouble?

Covariant redefinition equals subtyping, right? And subtypes can take the place of their supertypes!

What's the catch?

g4v3
  • 133
  • 2
  • 10

2 Answers2

1

The issue is not with covariance itself. (In particular, if it were contra-variance, Design-by-Contract would be impossible, because argument types in the features of descendant classes would not necessary have features available in their parents. With covariance there is no such a problem.)

Problematic is a combination of covariance with polymorphism. E.g.

class A feature
    foo (a: A) do a.bar end -- (1)
    bar do end
end
class B inherit A redefine foo end feature
    foo (a: B) do a.qux end -- (2)
    qux do end
end

Now the following code would crash:

a: A; b: B
...
create b
a := b
a.foo (create {A})

Indeed, a.foo would call version (2) because a is attached to an object of type B. However, the argument passed to this feature will be of type A. And A has no feature qux that leads to a run-time error. This kind of an error is know as a CAT-call (Changing Availability or Type).

A solution to this issue is to avoid using covariance together with polymorphism, i.e. a call should not be polymorphic or there should be no covariant redeclaration of arguments. The work on this solution is in progress.

Alexander Kogtenkov
  • 5,770
  • 1
  • 27
  • 35
0

"a call should not be polymorphic or there should be no covariant redeclaration of arguments."

How can you tell?

Let's change your example a bit:

buzz (a_a: A) do a_a.foo (create {A}) end

This looks innocent enough. But if buzz receives an argument of dynamic type B you still get the catcall. The author of buzz might well be in a situation where the existence of B is unknown.

I think you need to drop the "a call should not be polymorphic or " bit of the advice. Simply prohibit covariant redeclaration of arguments.