Подтвердить что ты не робот

Вывод типа в Java (à la С#)

С тех пор как я слышал о типе вывода (в Haskell), я жил под впечатлением, что Java - это полная противоположность, т.е. не имеет вывода типа. Недавно, хотя, у меня был момент аха, и понял, что Java использует вывод типа в своей реализации generics.

Затем я прочитал две статьи Гилада Брача (по-моему, одного из людей, стоящих за реализацией дженериков на Java, насколько я понимаю). Первая статья - это учебник о дженериках (PDF), в котором он явно говорит, что компилятор выведет фактический аргумент типа, используемый для замены параметра типа формата. Итак, там тип вывода в Java, но почему только для дженериков, почему не что-то вроде С# var ключевое слово? И это мой вопрос к вам.

Почему Java не имеет больше встроенного в компилятор вывода типа?

Я дам вам ответ, и это связано со вторым документом, который я прочитал, Pluggable Type Systems (PDF). Кажется, Гилад Брача считает, что часть вывода не должна быть частью компилятора, но функция IDE или аналогичная (раздел 4, пункт 6 в вышеупомянутой статье):

Улучшенный инженерный подход применять вывод типа как отдельный инструмент, доступный в среде IDE. Программисты, которые находят тип ввода аннотации утомительны могут вызвать inferencer по запросу.

Как вы думаете?

4b9b3361

Ответ 1

Ну, я думаю, что вывод типа в Java по историческим причинам в основном: как и подобает языку с сильными устаревшими ограничениями, улучшения Java сделаны осторожно и постепенно (как JCP, хотя некоторые улучшения вывода типа управляются пройти). В случае с дженериками давняя реализация GJ была тщательно оценена до включения в Java 5.

До выпуска Java 5 не было вывода типа в Java. (...) Когда generics (...) были введены в Java 5, язык сохранил это требование для переменных, методов и распределений. Но введение полиморфных методов (параметризованных по типу) диктует, что либо (i) программист предоставляет аргументы типа метода на каждом сайте вызова полиморфного метода, либо (ii) язык поддерживает вывод аргументов типа метода. Чтобы избежать создания дополнительной канцелярской нагрузки для программистов, разработчики Java 5 решили выполнить вывод типа для определения аргументов типа для вызовов полиморфных методов. (источник)

Но это не означает, что в Java существует сильная культура для всенаправленного вывода типа. По спецификация:

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

Я думаю, что более типичный вывод для Java был бы благом (Scala уже очень интересное улучшение в этом направлении). ИМХО, вывод типа делает цикл обратной связи с типом проверки менее механическим, будучи таким же простым, позволяя писать меньше типов, но заставляя вас проверять тип так же. Поскольку основное преимущество типов - направлять психический процесс поиска программ ( " позволяет писать в пространстве хорошо типизированных программ, а не в пространстве ascii turds), этот комфорт во взаимодействии с контролером типов кажется неоценимым: у вас есть средство проверки типов, которое проверяет, что вы думаете в хорошо типизированных условиях и готовит вас к этому, вместо того, чтобы заставлять вас учитывать его в каждой строке.

Теперь этап, на котором должен быть вывод типа, - это другой вопрос. Я думаю, что желание иметь "инференеры" отдельно от среды выполнения отвечает устаревшим соображениям: это позволяет вам требовать, чтобы у вас был алгоритм вывода типа, который всегда обратно совместим. Но тогда ключ становится тем, что выглядят ваши стандартные/основные библиотеки: источник, который вы публикуете и обмениваетесь с другими аннотированными или нет?

В то время как верно, что аннотированный источник может, быть ценно, проверяться по типу, независимо от силы вашего механизма вывода, я все равно хочу иметь тип inferencer в компиляторе, потому что это не только то, что я не хочу напишите List<CacheDecoratorFactory> cacheDecoratorFactories = new ArrayList<CacheDecoratorFactory>();, это не значит, что я не хочу его читать. Я также не хочу иметь дело с этим, когда я реорганизую ранее существовавший источник, если на то пошло. Мне понадобится стирание аннотаций типа "hider", прежде чем я взаимодействую с источником, но если механизм вывода типа не завершен, проблема аннотаций для стирания и обеспечения стирания, за которым следует восстановление типа, является биективным, становится тернистым (особенно если ваш механизм вывода не возвращает основной тип)... Если в любом случае нам нужно решить тернистую проблему, почему бы не сделать это хорошо, и как полный возможный алгоритм вывода типа? Моя догадка заключается в том, что прошлое определенного уровня качества (в частности, в отношении общности возвращаемых типов), устаревшие проблемы начнут исчезать.

Ответ 2

Вывод типа доступен в IntelliJ, возможно, в других IDE. Вы можете написать выражение (или использовать существующее) и выбрать "Ввести поле/Локальная переменная/Константа" и т.д., И это даст вам некоторые возможные варианты типов и некоторые предлагаемые имена. Если выражение появляется более одного раза, оно дает вам возможность заменить все вхождения. например У меня есть строка, которую я хочу превратить в параметр

myMethod();

public void myMethod() {
    "/tmp/20101112/data.file"
}

Я выбираю часть даты и <ctrl> + <alt> + P, и она предлагает тип int для добавления в качестве параметра. Он будет включать эту дату во всех абонентов.

myMethod(20101112);

public void myMethod(int date) {
    "/tmp/"+date+"/data.file"
}

Я помещаю "новый FileInputStream (" в начале и вводим локальную переменную ". <ctrl> + <alt> + V

    FileInputStream fileInputStream = new FileInputStream("/tmp/"+date+"/data.file");

В нем подчеркивается, что это может вызвать исключение, которое я могу автофиксировать несколькими способами. Я выбираю <alt> + <enter> и добавляю исключение в предложение throws метода.

myMethod(20101112);

public void myMethod(int date) throws FileNotFoundException {
    FileInputStream fileInputStream = new FileInputStream("/tmp/"+date+"/data.file");

IMHO, гораздо разумнее, чтобы IDE выполняла работу, поскольку она может делать гораздо более интерактивно, чем компилятор, и вы можете явно видеть, что ваши типы становятся.

Ответ 3

На самом деле это не ответ, но, с другой стороны, вы можете взглянуть на язык D. Это позволяет вам писать код следующим образом:

int*[6]*[wstring][]*[string]*[] myVar;
auto myVar2 = new typeof(myVar[0])[100]; // equivalent to: new int*[6]*[wstring][]*[string]*[]*[string]*[100]

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

Ответ 4

Это интересная, очень интересная тема, более связанная с исследованиями, чем с фактическим (то есть) программированием.

Прежде всего. О var в Java, на самом деле нет причин для его реализации, у них уже есть "технология". Однако обобщения находятся только в стороне компилятора системы, это означает, что во время выполнения VM просто использует ссылки на Object, и они соответствующим образом передаются из-за кода, введенного компилятором (опять же во время компиляции). В С#, однако, дженерики действительно живут после времени компиляции.

Во-вторых, об этой (очень интересной) статье Брача, вы, вероятно, должны взглянуть на наш проект StaDyn - язык программирования С#. Система типов фактически подключаема, т.е. Вы можете использовать ее, как в обычном С#, или вообще не использовать ее, и испытать полностью динамический язык.

http://www.reflection.uniovi.es/stadyn/