Pull to refresh

Comments 12

И как часто вам приходилось с такими вот финтами ушами играться, что это породило данную статью)) Просто розовые пони и драконы не существуют — точно также как и ваши примеры в реальной работе. Или статья заключается именно в этом?

Результат интересен именно как исследование. В реальной работе же полезно знать о ковариантности и контравариантности, всё остальное для души.
Хотел бы я посмотреть на команду, девлид которой вводит обязательное требование к типобезопасности всех билдеров.
Разумеется, в программе надо реализовать обработку ошибок. Если программа хочет вывести ошибку, она должна сформировать её (из имён классов) и вывести на экран. В тьюринг-машине надо реализовать байт-код, который бы поддерживал exception'ы, функции с параметрами, классы, наследование, темплетизацию…
В первой формуле раздела Subtyping Machines в правой части индекс разве не n?
Всё верно, там должен быть индекс n. Спасибо!
EDIT: поправил формулу в публикации
Я в джаве плохо разбираюсь, но разве тут не будет теряться информация о типе? То есть после вызова
Number firstNum(List<? extends Number> xs) {
    return xs.get(0);
}

Мы сразу теряем информацию о том, какой был тип, и после вызова метода нам снова нужно будет его скастовать явно. В шарпе я бы написал что-то типа
T firstNum<T>(List<T> xs) where T : Number {
    return  xs[0];
}

Который читается как «для любого списка элементов подтипа Number вернуть значение того же типа». Разве в джаве так нельзя указать? Я попробовал
<? extends Number> firstNum(List<? extends Number> xs) {
    return xs.get(0);
}

Но это вроде не то же самое.

В каком то смысле информация действительно теряется, но в данном контексте она и не нужна. Если нужно сохранение типа, то можно написать такой код:


<T extends Number> T firstNum(List<T> xs) {
    return xs.get(0);
}

Но я приводил пример не с этой целью. Рассмотрим такой код:


void query(Map<String, Object> parameters) { ... }

Метод принимает ассоциативный массив "параметров", значения которых могут иметь произвольные типы. Но если вдруг у нас в коде есть объект типа Map<String, String>, то мы не сможем передать его в метод query (типы не совпадают).


При этом если изменить сигнатуру метода на void query(Map<String, ? extends Object> parameters), то в него легко можно будет передать Map с любым типом значений, включая Map<String, String>.

Но ковариация тут и не нужна, просто указываем, что нам нужен объект с типом Т. Примеры опять же на шарпе, прошу извинить:
void Foo<T>(Dictionary<string, T> dictionary) {}


Ковариация интересна в рамках работы в теле одного метода, не пересекая его. Например:
void Main()
{
	IFoo<Object> iobj = null;
	IFoo<String> istr = null;

	// Присваивание работает благодаря ковариации
	iobj = istr;
}

interface IFoo<out T>
{
	T SomeValue { get;}
}

В этом случае через дженерики такой выразить не получится. Ну и классический случай, что массив значений X может безопасно считаться readonly-коллекцией базового типа
IEnumerable<object> foos = new int[] {1,2,3};

Верно, любой <? extends X> можно заменить введением дополнительного типа в сигнатуру метода, но я такой подход считаю менее удобным.

Ну, в этом видимо и различие языков. Мне например часто очень хочется узнать что за тип T был подставлен в этом месте. Без сигнатуры тут никак, увы.
Sign up to leave a comment.

Articles

Change theme settings