Eiffel: ковариантные недопустимые типы, передаваемые в качестве аргументов?

(выделено мной)

Ковариантное переопределение полей и функций не создает проблем, но ковариантное переопределение аргументов делает проблему, связанную с тем, что недопустимые типы могут быть переданы в качестве аргументов.

Но если ковариантное переопределение типов полей и функций не вызывает проблем, то почему ковариантное переопределение типа аргумента может вызвать проблемы?

Ковариантное переопределение равносильно подтипированию, верно? И подтипы могут занимать место своих супертипов!

В чем подвох?


person g4v3    schedule 13.12.2016    source источник


Ответы (2)


Проблема не в самой ковариации. (В частности, если бы это была контрвариантность, проектирование по контракту было бы невозможно, потому что типы аргументов в функциях классов-потомков не обязательно имели бы функции, доступные в их родителях. С ковариантностью такой проблемы нет.)

Проблемным является сочетание ковариантности с полиморфизмом. Например.

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

Теперь следующий код вылетит:

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

Действительно, a.foo вызовет версию (2), потому что a присоединен к объекту типа B. Однако аргумент, передаваемый этой функции, будет иметь тип A. И A не имеет функции qux, которая приводит к ошибке во время выполнения. Такая ошибка называется CAT-вызовом (Изменение доступности или типа).

Решение этой проблемы состоит в том, чтобы избежать использования ковариантности вместе с полиморфизмом, т. е. вызов не должен быть полиморфным или не должно быть ковариантного переобъявления аргументов. Работа над этим решением продолжается.

person Alexander Kogtenkov    schedule 13.12.2016

«вызов не должен быть полиморфным или не должно быть ковариантного переобъявления аргументов».

Как вы можете сказать?

Давайте немного изменим ваш пример:

buzz (a_a: A) сделать a_a.foo (создать {A}) конец

Это выглядит достаточно невинно. Но если buzz получает аргумент динамического типа B, вы все равно получаете освистывание. Автор шумихи вполне может оказаться в ситуации, когда существование B неизвестно.

Я думаю, вам нужно отказаться от совета "вызов не должен быть полиморфным" или ". Просто запретите ковариантное переобъявление аргументов.

person user2783273    schedule 14.12.2016