Comparator combinators
Tim Peierls
tim at peierls.net
Wed Aug 21 11:33:38 PDT 2013
Explicit comparingXxx, etc. is best.
On Wed, Aug 21, 2013 at 2:28 PM, Brian Goetz <brian.goetz at oracle.com> wrote:
> 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