Разве аргумент не соразмерный?
Я понимаю термины co-дисперсия и противоречие. Но есть одна маленькая вещь, которую я не могу понять. В курсе "Функциональное программирование в Scala" на coursera Мартин Ордерский упоминает, что:
Функции контравариантны в своих типах аргументов и ко-вариантах в их возвращаемые типы
Итак, например, в Java, пусть Dog
extends Animal
. И пусть функция будет:
void getSomething(Animal a){
и я вызываю вызов функции как
Dog d = new Dog();
getSomething(d)
Итак, в основном, что происходит, это Animal a = d
. И в соответствии с wiki ковариация - это "Преобразование шире к узкому". И выше мы переходим от собаки к животному. SO не является аргументом типа ковариантным, а не контравариантным?
Ответы
Ответ 1
Это как функции определены в Scala:
trait Function1 [-T1, +R] extends AnyRef
На английском языке параметр T1
является контравариантным, а тип результата R
является ковариантным. Что это значит?
Если какой-либо фрагмент кода требует функции типа Dog => Animal
, вы можете предоставить функцию типа Animal => Animal
, благодаря контравариантности параметра (вы можете использовать более широкий тип).
Также вы можете предоставить функцию типа Dog => Dog
, благодаря ковариации типа результата (вы можете использовать более узкий тип).
Это действительно имеет смысл: кто-то хочет, чтобы функция превращала собаку в любого животного. Вы можете предоставить функцию, которая преобразует любое животное (включая собак). Также ваша функция может возвращать только собак, но собаки все еще являются животными.
Ответ 2
Преобразование Dog
в Animal
преобразует узкие в более широкие, поэтому это не ковариация.
Ответ 3
Я помню, что меня смутило то самое предложение, когда я читал книгу Scala в 2007 году. Мартин поставляет ее так, как будто он говорит о языковой функции, но в этом предложении он только утверждает факт о функциях вообще, Scala, в частности, моделирует этот факт просто по регулярному признаку. Поскольку Scala имеет дисперсию объявления-сайта, выражение семантики является естественным для языка.
Java Generics, с другой стороны, поддерживает только разницу в использовании сайта, поэтому ближайшая к co/contravariance типа функции в Java заключается в том, чтобы вручную ее кодировать на каждом используемом сайте:
public int secondOrderFunction(Function<? super Integer, ? extends Number> fn) {
....
}
(предполагая, что для типа параметра и R
для типа возвращаемого значения соответственно объявлен интерфейс Function<P, R>
, P
). Естественно, поскольку этот код находится в руках клиента и вообще не относится к функциям, утверждение о дисперсии типа типа/возвращаемого типа не применимо к какой-либо языковой функции Java. Он применим только в более широком смысле, относящемся к характеру функций.
В Java 8 появятся закрытие, что подразумевает первоклассные функции, но, как следует из комментария Jörg ниже, реализация не будет включать полноценный тип функции.