Comparator combinators

Henry Jen henry.jen at oracle.com
Wed Aug 21 13:53:42 PDT 2013


Seems the consensus is converging to disambiguate with the method name, which I am OK with. In fact, we had done that before and revert back because people don't like it.

As mentioned several times, the not-intended boxing is the main concern. While I understand that IDE could help, I don't like to assume people will be using one(although most likely they are).

How often will we need to add these explicit type? Is that type harder to figure out than knowing what we are comparing?

Cheers,
Henry
 
On Aug 21, 2013, at 11:28 AM, 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