Рассмотрение дизайна API Java 8 Stream
, я был удивлен общей инвариантностью аргументов Stream.reduce()
:
<U> U reduce(U identity,
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
Казалось бы, более универсальная версия того же API могла бы применять ковариацию/контравариантность для отдельных ссылок на U
, например:
<U> U reduce(U identity,
BiFunction<? super U, ? super T, ? extends U> accumulator,
BiFunction<? super U, ? super U, ? extends U> combiner)
Это позволило бы сделать следующее, что невозможно в настоящее время:
// Assuming we want to reuse these tools all over the place:
BiFunction<Number, Number, Double> numberAdder =
(t, u) -> t.doubleValue() + u.doubleValue();
// This currently doesn't work, but would work with the suggestion
Stream<Number> stream = Stream.of(1, 2L, 3.0);
double sum = stream.reduce(0.0, numberAdder, numberAdder);
Обходной путь, используйте ссылки на методы для "принуждения" типов к целевому типу:
double sum = stream.reduce(0.0, numberAdder::apply, numberAdder::apply);
С# не имеет этой конкретной проблемы, поскольку Func(T1, T2, TResult)
определяется следующим образом, используя дисперсию объявления-сайта, что означает, что любой API, использующий Func
, получает это поведение бесплатно:
public delegate TResult Func<in T1, in T2, out TResult>(
T1 arg1,
T2 arg2
)
Каковы преимущества (и, возможно, причины решений EG) существующего дизайна над предлагаемым дизайном?
Или, по-другому, какие предостережения предлагаемого дизайна, которые я мог бы игнорировать (например, трудности ввода вывода, ограничения параллелизации или ограничения, характерные для операции сокращения, такие как, например, ассоциативность, предвидение будущего сайта объявления Java дисперсия на BiFunction<in T, in U, out R>
,...)?