Comparator combinators
Brian Goetz
brian.goetz at oracle.com
Wed Aug 21 11:28:16 PDT 2013
Waiting for input on this.
I'm torn. On the one hand, we'd be publishing a new, lambda-centric API
that doesn't conform to our "safe overloading" rules, and for which
users would have to use explicit lambdas in the cases where method
references aren't practical.
On the other, if we rename the primitive versions to
comparingXxx/thenComparingXxx, we're creating a different sort of risk
-- users will say
comparing(Person::getAge)
and get boxing when they didn't intend (this is
comparing(Function<Person,Integer>), when they probably wanted
comparingInt(ToIntFunction<Person>)). Though this would be easy for
IDEs to detect and suggest a replacement.
I think the responsible thing to do is still probably to disambiguate by
method name -- comparingInt, thenComparingLong, etc. Which isn't pretty
but seems to be the new equilibrium (overloading and inference are in
opposition; adding more inference means we can tolerate less overloading.)
If there's no input, an executive decision will be made...
On 8/14/2013 3:49 PM, Brian Goetz wrote:
> This may well be our last API loose end...
>
> We currently have a pile of Comparator combinators, all currently called
> comparing() or thenComparing(). Regardless of whether we choose to go
> forward with the simplified overloading plan, these overloads have a
> problem: for implicit lambdas, we can't distinguish between
>
> comparing(T->U)
> and
> comparing(T->int)
>
> because we don't type-check the body of the lambda until we do overload
> selection, and don't do overload selection based on whether there are
> type errors in the body (this was roundly rejected as being too
> brittle). So for lambdas like:
>
> comparing(x -> x.size())
>
> we've got a circularity -- even under the older, more complex scheme.
>
> We'd thought perhaps that, if we adopted the heuristic that we can
> eagerly give a type to method reference that refers to a non-overloaded
> method (e.g., Person::getAge), then cases like
>
> comparing(Person::getAge)
>
> can be handled, and this might take some of the pressure off the problem.
>
> For lambdas (with either approach) you can always get what you want with
> an explicit lambda:
>
> comparing((Person p) -> p.getAge())
>
> since this can be type-checked early.
>
> So the question is, is this good enough, even though it falls afoul of
> the overloading guidelines for implicit lambdas? Or, should we mangle
> the names of the methods?
>
> This question comes down to whether we think its better to force
> everyone to explicitly pick a method, but then supporting implicit lambdas:
>
> comparingInt(x -> x.size())
>
> or forcing users to use non-ambigous method refs or explicit lambdas:
>
> comparing(Person::getAge)
> or
> comparing((Person p) -> p.getAge())
>
> Which disambiguation approach is worse?
>
More information about the lambda-libs-spec-observers
mailing list