The following signature is valid and commonly used in Scala:
trait Collection[A] {
def reduceLeft [B >: A] (f: (B, A) => B): B
}
However, since >:
is the Scala equivalent of super
in Java, my first idea to convert this signature (replacing the function type with BiFunction
and making use of Use-Site variance annotations aka Bounded Wildcards) would be
interface Collection<A> {
<B super A> B reduceLeft(BiFunction<? super B, ? super A, ? extends B> mapper)
}
But oh no! The compiler complains about the super
token in <B super A>
because you can't have lower-bounded type variables! Now how would I write this method in Java code without having to time-travel back to when generics didn't exist in the Java world?
Yes, I know that you think I could use B extends A
, but that is not the same thing, as shown by my implementation:
public <R extends E> R reduceLeft(BiFunction<? super R, ? super E, ? extends R> mapper)
{
if (this.isEmpty())
{
return null;
}
Iterator<E> iterator = this.iterator();
R first = iterator.next(); // doesn't work, but would if R was a super-type of E (R super E)
while (iterator.hasNext())
{
mapper.apply(first, iterator.next());
}
return first;
}
Instead, I had to use this slightly more restricted version:
public E reduceLeft(BiFunction<? super E, ? super E, ? extends E> mapper)
{
if (this.isEmpty())
{
return null;
}
Iterator<E> iterator = this.iterator();
E first = iterator.next();
while (iterator.hasNext())
{
first = mapper.apply(first, iterator.next());
}
return first;
}