Pull to refresh

Comments 24

Насчёт пункта 2 — тут вполне логично всё. Если мы используем wildcard, то мы явно заявляем компилятору, что мы не знаем соответствующий тип. ? до некоторой степени эквивалентен ? extends Object, что делает Ref<?> ковариантным; следовательно, методы, которые принимают значение типа-параметра в качестве аргумента вызывать больше нельзя. В противном случае в компиляторе должен быть механизм отслеживания того, откуда какое значение пришло, что в общем случае мне кажется эквивалентным проблеме останова.


Насчёт 3 пункта мне тоже не кажется наличие проблемы очевидной. В конце концов, вы там мешаете дженерики и сырые типы, чего делать очень не рекомендуется. Решение, как вы заметили — не использовать сырые типы. Про сырые типы лучше вообще забыть в аспекте написания кода, это страшенный костыль для обратной совместимости.


Первое это вообще треш, да. Никогда правда с таким не сталкивался.

UFO just landed and posted this here

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

Мне кажется, здесь очень простая логика: любой сырой тип в выражении эквивалентен заявлению "я хочу работать в рамках java <1.5". Просто, понятно, легко запомнить.


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


Даже если вам в код пришел сырой тип из какой-нибудь легаси библиотеки — гораздо проще его руками привести к "нужному" параметризованному, и дальше не знать горя (тут должна быть саркастическая усмешка).

В противном случае в компиляторе должен быть механизм отслеживания того, откуда какое значение пришло
А почем бы и нет: https://pastebin.com/ELrG1kdG.
Это, конечно, не java, но примеры систем типов, в которых это отслеживается, существуют.

Удивлён, что скала такое умеет. Это не Dotty, случайно?

А, вот оно что. Я пристально за дотти не слежу, получается что там как-то унифицировали типовые параметры и ассоциированные типы? Я ещё удивился синтаксису refA.T/refB.T, который вроде как подразумевает что T это type T а не параметр. Про ассоциированные типы у меня с самого начала была мысль, да, но тут речь шла про параметры всё-таки)

Принципиальной разницы между type members и type parameters в общем-то нет — они это продемонстрировали унификацией.
И в scala зачастую поднимали type members в type parameters — см Aux паттерн в shapeless.

Но если придираться, то можно сказать, что wildcard type в Dotty просто нет: Dropped: Existential Types.

Понятно, спасибо за ссылку! Надо будет про отличия дотти почитать поподробнее.

Коллега, извиниие, если грубо, но учите матчасть.
Согласен с предыдущим комментатором: во всех случаях действуют обычные правила Type Erasure. В последнем надо поменять местами ограничения: чистка идёт до первого параметра. Про первый я тоже не совсем понял, но посмотрю, когда буду у компа.

Я не утверждаю, что это не по спецификации. Просто сама спецификация местами странная очень.
Например, в случае 3, на мой взгляд, спецификация идёт вразрез со здравым смыслом, да и в случае 1 тоже.
А в последнем, если поменять местами ограничения, то отвалятся референсы для другого типа, так что хорошим решением это тоже не назовёшь.
третий случай как раз самый понятный, вы из ссылки на интерфейс пытаетесь получить ссылку на реализацию что противоречит идеи интерфейсов, в силу особенностей явы это технически возможно но в общем не приветствуется, перекрыв метод вы принудили компилятор сделать это, вы думаете что это должно быть сделано автоматически? совершенно не факт, допустим компилятор делает как вам надо, а мне на оборот нужно чтобы getList() возвращал интерфейс мне также перекрывать метод?, получается шило на мыло.
идёт вразрез со здравым смыслом, да и в случае 1 тоже.

Чего бы это вдруг?
Тип переменной clazz — raw type.
Либо программист может использовать generics и тогда это будет явно указано при декларации clazz.
Либо же программист попал в тяжёлые жизненные обстоятельства и использовать generics не может, в этом случае и у методов тоже никаких generics быть не может.

Вот почему стирание типа T должно тянуть за собой стирание совершенно с ним не пересекающегося типа A? Я не считаю это логичным.
И да, обстоятельства бывают разные и часто в проектах можно встретить raw types

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


Ответ: профит очень мал. Гораздо проще привести сырой тип руками к нужному параметризованному. Если у вас в проекте легаси код с сырыми типами — сделайте вокруг него обертку-адаптер.


Т.е. моя идея в том, что никто никогда не обещал сохранять сырые типы как "first class citizen". Их время ушло, давай, до свидания. Компилятор поддерживает их для обратной совместимости, но не более.

В целом я с вами согласен, сырыми типами пользоваться не стоит.
Но, к сожалению, класс Class (как минимум) слишком часто используется без параметра. Получается, что компилятор вынуждает нас писать <?> в месте неизвестного типа вместо того, чтобы разрешить вообще игнорировать параметр.
Я ща доку посмотрел так там так и написано
For example, the type of String.class is Class. Use Class<?> if the class being modeled is unknown.

т.е. просто Class даже не рассматривается.
И это логично раз getClass возвращает Class<?>

эх маловато времени на редактирование
Вот почему стирание типа T должно тянуть за собой стирание совершенно с ним не пересекающегося типа A?

Ну как же не пересекающегося?
Тип T параметризует класс, тип A параметризует метод, вложенный в этот класс.


У меня не получается придумать пример, в котором при декларации типа переменной использовать generics нельзя, а при вызове метода объекта, ссылка на который хранится в данной переменной, — можно.


А раз такого случая нет, то и делать поддержку в компиляторе для этого случая нецелесообразно.

Вы думаете, все эти странности просто так от хотения взяты? Отправьтесь в 2004 год, когда выходила Java 5, и скажите — «А давайте забьём на совместимость с Java 1.4 и перепишем JVM» — чем вас закидают?
Небольшое дополнение к первому примеру: использование raw-типов удаляет даже типоаргументы:
class A<T> {
	List<Integer> list = Arrays.asList(1);
}

// Type mismatch: cannot convert from Object to Integer
Integer i = new A().list.get(0);

Да, в дженериках встречаются странности, иногда контринтуитивное поведение, но все проблемы разрешаются в compile-time.

Sign up to leave a comment.

Articles