Я пытался понять, почему JDK 8 Lambda Expert Group (EG) решила не включать новый тип функции в язык программирования Java.
Просматривая список рассылки, я нашел ветку с обсуждением удаления типов функций .
Многие из утверждений для меня неоднозначны, возможно, из-за отсутствия контекста, а в некоторых случаях из-за моих ограниченных знаний о реализации систем типов.
Тем не менее, есть пара вопросов, которые, я считаю, я могу смело сформулировать на этом сайте, чтобы помочь мне лучше понять, что они имели в виду.
Я знаю, что могу задавать вопросы в списке рассылки, но ветка устарела, и все решения уже приняты, поэтому есть вероятность, что меня проигнорируют, прежде всего, увидев, что эти парни уже запаздывают со своими планами.
В своем ответе, чтобы поддержать удаление типов функций и одобрить использование типов SAM, Брайан Гетц говорит:
Нет овеществления. Была длинная тема о том, насколько полезно было бы преобразовывать типы функций. Без реализации, типы функций не работают.
Я не мог найти нить, которую он упоминает. Теперь я могу понять, что введение структурного функционального типа может подразумевать определенные сложности в Java, в основном системе номинальных типов, но я не могу понять, насколько параметризованные типы SAM отличаются с точки зрения реализации.
Разве они оба не подвержены одинаковым проблемам овеществления? Кто-нибудь понимает, как типы функций отличаются от параметризованных типов SAM с точки зрения реализации?
В другом комментарии Гетц говорит:
Существует два основных подхода к типированию: номинальный и структурный. Личность номинала основана на его имени; идентичность структурного типа основана на том, из чего он состоит (например, «tuple of int, int» или «function from int to float»). Большинство языков выбирают в основном номинальные или в основном структурные; не так много языков, в которых успешно сочетаются номинальная и структурная типизация, кроме «по краям». Java почти полностью номинальна (за некоторыми исключениями: массивы являются структурным типом, но в нижней части всегда есть номинальный тип элемента; дженерики также имеют сочетание номинального и структурного типов, и это на самом деле является частью источника многих жалоб людей на дженерики.) Привлечение структурной системы типов (типов функций) на Java ' Система номинального типа означает новые сложности и крайние случаи. Стоит ли преимущество типов функций?
Те из вас, кто имеет опыт внедрения систем типов. Вы знаете какие-либо примеры этих сложностей или крайних случаев, которые он упоминает здесь?
Честно говоря, меня смущают эти утверждения, когда я считаю, что такой язык программирования, как Scala, полностью основанный на JVM, имеет поддержку структурных типов, таких как функции и кортежи, даже с учетом проблем с реализацией базовой платформы.
Не поймите меня неправильно, я не говорю, что тип функции должен быть лучше, чем тип SAM. Я просто хочу понять, почему они приняли это решение.
источник
Ответы:
Подход SAM на самом деле чем-то похож на то, что Scala (и C ++ 11) делают с анонимными функциями (созданными с помощью
=>
оператора Scala или[]()
синтаксиса C ++ 11 (лямбда)).Первый вопрос, который нужно ответить на стороне Java, заключается в том, будет ли возвращаемый тип лямбда-оператора новым типом-примитивом, например
int
илиbyte
, или каким-либо типом объекта. В Scala, там нет ни одного примитивного типа - даже целое число является объектом классаInt
- и функция не отличается, являющиеся объектами классаFunction1
,Function2
и так далее, в зависимости от количества аргументов функции принимает.C ++ 11, ruby и python также имеют лямбда-выражения, которые возвращают объект, который можно вызвать явным или неявным способом. Возвращенный объект имеет некоторый стандартный метод (например,
#call
который можно использовать для вызова его как функции. Например, C ++ 11 используетstd::function
тип, который перегружается,operator()
так что вызовы метода вызова объекта даже выглядят как вызовы функций в текстовом виде. :-)Когда новое предложение для Java становится беспорядочным, используется структурная типизация, позволяющая назначать такой метод другому объекту, например,
Comparator
который имеет единственный основной метод с другим именем . Хотя это концептуально неприглядное в некотором смысле, это делает означает , что полученный объект может быть передан в существующие функции , которые принимают объект для представления обратного вызова, компаратора, и так далее, и ожидать , чтобы быть в состоянии назвать вполне определенный сингл метод, такой как#compare
или#callback
. Уловка переопределения в C ++operator()
аккуратно уклонилась от этой проблемы еще до C ++ 11, поскольку все такие параметры обратного вызова можно было вызывать одинаково, и, следовательно, STL не требовал настройки, позволяющей использовать лямбда-выражения C ++ 11 сsort
и так далее. Java, не использовавшая стандартного именования для таких объектов в прошлом (возможно, из-за того, что ни одна хитрость, такая как перегрузка операторов не делала очевидным единый подход), не столь удачна, так что этот хак не позволяет им менять целый ряд существующих API. ,источник
java.util.Function2<T1, T2, R>
Java 1.0, тогда не было бы никакогоComparator
интерфейса, вместо этого все эти методы взяли быFunction2<T1, T2, int>
. (Ну, было бы целое множество интерфейсов, например,Function2TT_int<T1, T2>
из-за примитивов, но вы понимаете мою точку зрения.)