Перейти к содержанию

Совместимость типов на основе вариантности

Помимо того, что совместимость типов зависит от вида типизации, которая была подробно разобрана в главе Совместимость типов на основе вида типизации, она также может зависеть от такого механизма, как вариантность.

Вариантность

Вариантность — это механизм переноса иерархии наследования типов на производные от них типы. В данном случае производные не означает связанные отношением наследования. Производные, скорее, означает определяемые теми типами, с которых переносится наследование.

Если вы впервые сталкиваетесь с этим понятием и определение вариантности кажется бессмысленным набором слов, то не стоит расстраиваться, эта тема очень простая, в чем вы сами скоро убедитесь.

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

Но прежде чем познакомиться с каждым из этих видов вариантности отдельно, стоит сделать некоторые уточнения касательно иерархии наследования.

Иерархия наследования

Иерархия наследования — это дерево, с расположенным вверху корнем или самым базовым типом (менее конкретный тип), ниже которого располагаются его подтипы (более конкретные типы). В случаях преобразования подтипа к базовому типу говорят, что выполняется восходящее преобразование (upcasting). И наоборот, когда выполняется приведение базового типа к его подтипу, говорят что выполняется нисходящее приведение (downcasting). Отношения между супертипом и его подтипом описываются как отношения родитель-ребенок (parent-child). Отношения между родителем типа и его ребенком описываются как предок-потомок (ancestor-descendant). Кроме того, при логическом сравнении тип, находящийся выше по дереву, больше (>) чем тип, находящийся ниже по дереву (и наоборот). Можно сказать, что parent > child, child < parent, ancestor > descendant, descendant < ancestor. Все это представлено на диаграмме ниже.

Иерархия наследования

Ковариантность

Ковариантность — это механизм, позволяющий использовать более конкретный тип там, где изначально предполагалось использовать менее конкретный тип. Простыми словами, совместимыми считаются типы, имеющие отношения A > B и A = B.

Ковариантность

Ковариантность не рекомендуется в местах, допускающих запись. Чтобы понять смысл этих слов, ниже представлена диаграмма, которая иллюстрирует, как через базовый тип можно добавить в массив с подтипом другой, несовместимый подтип, и тем самым нарушить типобезопасность программы.

Ковариантность

Ковариантность рекомендуется применять в местах, допускающих чтение.

Контравариантность

Контравариантность — это противоположный ковариантности механизм, позволяющий использовать менее конкретный тип там, где изначально предполагалось использовать более конкретный тип. Другими словами, совместимыми считаются типы, имеющие отношения A < B и A = B.

Контравариантность

Контравариантность не рекомендуется применять в местах, допускающих чтение, и наоборот, рекомендуется применять в местах, допускающих запись.

Инвариантность

Инвариантность — это механизм, позволяющий использовать только заданный тип. Совместимыми считаются только идентичные типы A = A.

Инвариантность

Бивариантность

Бивариантность — это механизм, который является представлением всех перечисленных ранее видов вариантности. В его случае совместимыми считаются любые из перечисленных ранее варианты типы A > B, A < B и A = B.

Бивариантность

Бивариантность является самым нетипобезопасным видом вариантности.

Комментарии