apply
Brian Goetz
brian.goetz at oracle.com
Sun Dec 16 18:07:43 PST 2012
OK, let's try to get this all in one place. Mostly a defense of the
status quo but there's some possibly good news at the end for apply fans.
1. Functional interfaces are special interfaces, but they are
interfaces. They can be implemented with lambdas, but they can also be
implemented by anonymous classes or implemented by classes with other
methods. Choosing sensible method names is a key part of API design;
there's a reason why we called the method in Runnable "run" and not
"apply". Run is a more descriptive name. One could design a library
where all methods are named "Harold", but it would be hard to write and
hard to use. And there are likely to be functional interfaces where
"apply" is an outright terrible name for what the thing does, and the
"all same" rule will feel pretty constraining.
2. Choosing nominal function types was a compromise -- a big one.
Structural function types are better than nominal ones in almost every
way. (Reminder: we went this way because erased and always-boxed
structural function types would *really* suck.) One of the few
advantages of nominal function types is that they have a name. Naming
them all Harold seems like deciding that since we chose a route with
disadvantages, we don't deserve any of the few remaining advantages.
3. Naming all SAM methods Harold slams the door on implementing many
combinations of SAMs in a single class, or having certain SAMs extend
each other. Again, in a pure functional world, the notion of
implementing multiple function types doesn't make much sense. But,
functional interfaces are interfaces, and objects may very well want to
implement multiple functional interfaces. Naming them all Harold means
that some combinations can be implemented this way, but some not, which
is a half-here, half-there state of affairs.
An obvious example is:
interface SupplierOfBoxedIntegers {
Integer apply();
}
interface DispenserOfInts {
int apply();
}
(First of all, apply is a terrible name for this class.) But more
importantly, no class can implement both, even though it might be
entirely reasonable for a class IntFlinger to implement all manner of
"give me an integer" methods, to maximize compatibility with / minimize
needed adaptation for multiple libraries that use a dispenser of
integers. If they are all called Harold, IntFlinger is out of luck.
In this example, the two functions that IntFlinger wants to implements
are basically the same function modulo boxing. But, sometimes you may
want to implement mutiple SAMs because their semantics are coupled
through the semantics of your class. For example:
class MapMembershipArbiter<K,V> {
Map<K,V> m;
implements Predicate<K>, Function<K,V> {
boolean test(K k) { return m.containsKey(k); }
V apply(K k) { return m.get(k);
}
If both methods were named apply, you couldn't do this.
Now, you might say "that's a stupid example" (and you might be right!)
But, the "all different" rule allows for the possibility that this might
actually be reasonable in some configuration; the "all same" rule
ensures that this can never happen.
That said, I am not unsympathetic (well, unless you don't use an IDE, in
which case I'm completely unsympathetic.) I do find myself tripping
over UnaryOperator.operate vs Function.apply since they're both just so
functiony. And here's where there might be some good news for you.
Since we currently have
interface UnaryOperator<T> extends Function<T,T>
then it actually is quite reasonable for UnaryOperator to adopt the name
from Function, since there is no way to implement UnaryOperator without
implementing Function. In which case some of the offenders --
Unary/BinaryOperator -- can go away.
Similarly, SAMs of different arities can safely use the same name. So
Function and BiFunction both use the same name.
On 12/16/2012 5:10 PM, Doug Lea wrote:
>
> (Still in the midst of the painful setup allowing
> JDK8 j.u.c builds to track lambda-libs...)
>
> Could someone please explain clearly and compellingly why we are using
> different method names for all the functional forms in java.util.function
> instead of just "apply"?
> Does anyone think that other users won't find this very annoying?
>
> -Doug
More information about the lambda-libs-spec-observers
mailing list