Варіантність — у програмуванні, спосіб перенесення успадкування типів на нові типи, параметризовані попередніми (контейнери, узагальнені типи, делегати).

Терміни виникли від термінів теорії категорій «коваріантний» та «контраваріантний» функтор.

Визначення В системі типів мови програмування, конструктор типів є: коваріантним — якщо він зберігає порядок типів (від похідних до базового); контраваріантним — якщо він змінює порядок типів на протилежний; біваріантним — якщо прямий і обернений порядок справедливі одночасно. інваріантним чи неваріантним — якщо він не підпадає під попередні варіанти.

Приклади на C# Наприклад, у C#, якщо Cat це підтип Animal, тоді: IEnumerable<Cat> це підтип IEnumerable<Animal>. Підтипність збережено, бо IEnumerable<T> коваріантний за T. Action<Animal> підтип Action<Cat>. Підтипність обернено, бо Action<T> контраваріантний за T. Ані IList<Cat>, ані IList<Animal> не є підтипом іншого, бо IList<T> інваріантний за T. Варіантність узагальнених інтерфейсів C# визначається через використання атрибута out (коваріантний) або in (контраваріантний) для (нуля чи більше) його параметрів типів. Для кожного промаркованого в такий спосіб параметра, компілятор перевіряє, не дозволячи жодного порушення, що використання глобально цілісне. Згадані інтерфейси означено як IEnumerable<out T>, Action<in T> і IList<T>. Типи з більш ніж одним параметром-типом можуть вказувати різні варіантності для різних параметрів-типів. Наприклад, тип-делегат Func<in T, out TResult> представляє функцію з контраваріантним входовим параметром типу T і коваріантним параметром типу результату TResult.Func<T, TResult> Delegate  — MSDN Documentation

Варіантність контейнерів Якщо типи та наслідують тип , конструктором масивів з типу утворимо тип («масив звірів»). Ми можемо використовувати його: коваріантно: вважаючи що є представником контраваріантно: вважаючи що є представником інваріантно: вважаючи що не є представником а також не є представником . Залежно від типу операцій, що будуть проводитись над масивом ми можемо використовувати різну варіантність: якщо тільки читати елементи масиву, то безпечно використовувати його коваріантно, оскільки є представником ; якщо тільки записувати чи передавати елементи масиву то безпечно використовувати його контраваріантно, щоб не було можливості в масив записати елемент типу ; якщо ж потрібно читати та записувати елементи масиву, то безпечно використовувати його тільки інваріантно. Також можна реалізувати два незалежні інтерфейси коваріантний Producer<T> для читання та контраваріантний Consumer<T> для запису елементів.

Масиви є коваріантними в Java, C# та інваріантними в C++.

Варіантність функційних типів Функційні типи є коваріантними за типом результату та контраваріантними за типами аргументів.

Тобто функції типу та успадковують тип та можуть безпечно використовуватись там де очікувався базовий тип.

Варіантність при успадковуванні C++, починаючи зі стандарту 1998 року, підтримує коваріантність при заміщенні віртуальних методів: class X {}; class Y : public X {};

class A { public: virtual X* f() { return new X; }

class B : public A { public: virtual Y* f() { return new Y; } // заміщуючи метод, можна повернути уточнений тип результату

В таблиці описано варіантність при заміщенні методів для різних мов програмування: тип аргумента тип результату C# інваріантний інваріантний C++ (з 1998), Java (з J2SE 5.0), Scala, D інваріантний коваріантний Sather контраваріантний коваріантний Eiffel коваріантний коваріантний

Варіантність шаблонних типів В деяких мовах програмування, що підтримують параметричний поліморфізм, можливо вказати варіантність шаблонного типу за параметром. Це можливо: при оголошенні шаблонного типу (як в C#) чи при створенні (використанні) конкретного типу на основі шаблонного (як у Java).

Задання варіантності при оголошенні в C# це можливо тільки для інтерфейсів (ключовими словами та ), в Scala та OCaml (ключовими словами та). Якщо варіантність не задано, то тип вважатиметься інваріантним.

Приклад interface IEnumerator<out T> { T Current { get; } bool MoveNext(); } вважатиметься успадкованим від .

Задання варіантності при використанні Задання варіантності при створенні кожного конкретного типу є гнучкішим. Воно дає змогу автору класу не оголошувати декілька інтерфейсів з різною варіантністю. В Java варіантність задається разом із заданням обмежувального типу: буде коваріантним типу елемента; буде контраваріантним типу елемента. При заданні варіантності буде заборонено використовувати методи класу з різною варіантністю.

Примітки

Джерела http://msdn.microsoft.com/ru-ru/library/dd799517.aspx Коваріантність і контраваріантність в шаблонах. http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx Covariance and Contravariance in C#, Part Two. Eric Lippert.