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