Почему стирание осложняет реализацию типов функций?
Ответ 1
То, как я это понимаю, заключается в том, что они решили, что благодаря стиранию было бы грязно идти по пути " типов функций", например. делегаты в С#, и они могут использовать лямбда-выражения, что просто упрощает синтаксис одного абстрактного метода.
Делегаты в С#:
public delegate void DoSomethingDelegate(Object param1, Object param2);
...
//now assign some method to the function type variable (delegate)
DoSomethingDelegate f = DoSomething;
f(new Object(), new Object());
(здесь еще один пример http://geekswithblogs.net/joycsharp/archive/2008/02/15/simple-c-delegate-sample.aspx)
Один аргумент, который они указали в документах Project Lambda:
Стираются общие типы, которые выставляют дополнительные места, где разработчики подвергаются стиранию. Например, это не было бы можно перегрузить методы m (T- > U) и m (X- > Y), что было бы запутанным.
раздел 2 в: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html
(Окончательный синтаксис лямбда-выражений будет немного отличаться от приведенного выше документа: http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/003936.html)
(x, y) => { System.out.printf("%d + %d = %d%n", x, y, x+y); }
В целом, мое лучшее понимание заключается в том, что только часть синтаксиса, которая может, на самом деле, будет использоваться. То, что Neal Gafter, скорее всего, имело в виду, заключалось в том, что невозможность использования делегатов затруднит адаптацию стандартных API-интерфейсов к функциональному стилю, а не к тому, что обновление javac/JVM будет более сложным.
Если кто-то поймет это лучше меня, я буду рад прочитать его отчет.
Ответ 2
Goetz расширяет рассуждения в Состояние лямбды 4-е изд.:
Альтернативный (или дополнительный) подход к типам функций, предложенные некоторыми ранними предложениями, заключались бы в том, чтобы представить новую, тип структурной функции. Тип типа "функция из строки и Объект int" может быть выражен как (String, Object) → int. идея была рассмотрена и отвергнута, по крайней мере на данный момент, из-за нескольких Недостатки:
- Это добавит сложности в систему типов и продолжит смешение структурных и номинальных типов.
- Это приведет к расхождению стилей библиотеки - некоторые библиотеки будут продолжать использовать интерфейсы обратного вызова, в то время как другие будут использовать структурные типы функций.
- Синтаксис может быть несовместимым, особенно когда отмечены исключения.
- Маловероятно, что было бы представление во время выполнения для каждого отдельного типа функции, что означает, что разработчики будут и ограничен стиранием. Например, это было бы невозможно (возможно удивительно) к методам перегрузки m (T- > U) и m (X- > Y).
Итак, вместо этого мы выбрали путь "использовать то, что вы знать", поскольку существующие библиотеки широко используют функциональные интерфейсы, мы кодифицируем и используем этот шаблон.
Чтобы проиллюстрировать, вот некоторые из функциональных интерфейсов в Java SE 7 которые хорошо подходят для использования с новыми языковыми особенностями; следующие примеры иллюстрируют использование нескольких из них.
- java.lang.Runnable
- java.util.concurrent.Callable
- java.util.Comparator
- java.beans.PropertyChangeListener
- java.awt.event.ActionListener
- javax.swing.event.ChangeListener
- ...
Обратите внимание, что стирание является лишь одним из соображений. В общем, лямбда-подход Java идет в другом направлении от Scala, а не только от типизированного вопроса. Это очень Java-ориентированный.
Ответ 3
Возможно, потому, что вы действительно хотели бы быть типом Function<R, P...>
, который параметризуется с типом возврата и некоторой последовательностью типов параметров. Но из-за стирания у вас не может быть такой конструкции, как P...
, потому что она может превращаться только в Object[]
, которая слишком свободна, чтобы ее можно было использовать во время выполнения.
Это чистая спекуляция. Я не теоретик типа; я даже не играл по телевизору.
Ответ 4
Я думаю, что он имеет в виду в этом заявлении, что во время выполнения Java не может отличить эти два определения функций:
void doIt(List<String> strings) {...}
void doIt(List<Integer> ints) {...}
Потому что во время компиляции информация о том, какие типы данных содержит список, стирается, поэтому среда выполнения не сможет определить, какую функцию вы хотите вызвать.
Попытка скомпилировать оба этих метода в одном классе вызовет следующее исключение:
doIt(List<String>) clashes with doIt(List<Integer); both methods have the same erasure