Comparator combinators

Sam Pullara spullara at gmail.com
Wed Aug 21 14:18:05 PDT 2013


I think the IntFunction version will be used more than any other
version. We could probably name that one comparing and name the other
ones with their types, e.g. comparingObject.

Sam

> On Aug 21, 2013, at 2:09 PM, Henry Jen <henry.jen at oracle.com> wrote:
>
> 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