LJC Lambdas Hackday

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Jun 4 07:26:37 PDT 2012


Hi David,
The kind of local technique you describe in your email has been on the 
table for quite some time. The only thing about it that makes us 
skeptical is its brittleness - i.e. if one day we would need to add 
another overload for 'into' - all clients using diamond will be broken.

Maurizio

On 04/06/12 04:39, David Conrad wrote:
> On Tue, 29 May 2012 14:35:16 +0100, Maurizio Cimadamore<
> maurizio.cimadamore at oracle.com>  wrote:
>
>> On 29/05/12 14:30, Richard Warburton wrote:
>>> 1. Target typing for diamond operators being passed into methods
>>> doesn't seem to work quite right at the moment.
>> Thanks for the feedback - the rationale for the current compiler
>> behaviour is explained in more details here:
>>
>> http://mail.openjdk.java.net/pipermail/lambda-dev/2012-May/004951.html
>>
>> Maurizio
>>
>>
> And on Tue, 29 May 2012 10:11:18 -0400, Brian Goetz<brian.goetz at oracle.com
>> wrote:
>> I wish we could consider this a simple bug, but as Maurizio points out,
>> this is a pretty big leap from local type inference towards more global
>> type inference.  We're evaluating our options here, but if we could have
>> fixed this already, we would have :(
>>
>>
> I think you can do better. I'll explain below, but first I want to pull in
> the
> content from Maurizio's link, above:
>
>
> On Sun May 27 04:03:41 PDT 2012, Maurizio Cimadamore<
> maurizio.cimadamore at oracle.com>  wrote:
>> m(List<String>  ls) { ... }
>>
>> m(new ArrayList<>)
>>
>> If you have inference variables on both ends, you have an inference
>> cycle. Now, since Java overload resolution is a function of argument
>> types only (the target type of the assignment is only considered at a
>> later stage), we are not supposed to look into that during overload
>> resolution.
>>
>> It's also a problem of whether we want inference to be more global vs.
>> keeping it local - your case might look reasonable enough - but then
>> what about:
>>
>> List<String>  ls = m(m(m(m(ArrayList<>))));
>>
>> Making inference more powerful will make those problems disappear, that
>> will have other side-effects - for instance the fact that you will get
>> strange error messages in unexpected places (as the compiler 'delays'
>> the time at which inference is performed to wait for some constraints).
>
> Okay, so there are two ways to fix this. One is to use more powerful,
> global type inference, but that has undesirable effects. But look back
> at the previous paragraph: "overload resolution is a function of argument
> types only". Overload resolution? I've tripped over the same thing that
> Richard Warburton did, and it amounts to this:
>
> public static void main(String[] args) {
>      Set<Integer>  set = Arrays.iterable(args)
>          .map(Integer::new)
>          .into(new TreeSet<>());
> }
>
> So to complete overload resolution on Iterable::into the compiler needs
> to know the argument types, and assumes TreeSet<Object>  because
> it doesn't yet know what method it's dealing with, and so cannot infer
> anything better than Object for the diamond syntax.
>
> Okay, now go open up Iterable.java and count the number of into
> methods. :)  (Forgive me for being overly cute; couldn't resist.)
>
> If the compiler short-circuits overload resolution in the case (and only
> the case) where there is one-and-only-one method by that name, it
> can handle this or even m(m(m(m(new ArrayList<>())*, but not:
>
>> List<String>  ls = m(m(m(m(ArrayList<>))));
> In this case, the type is known only by the target of the assignment.
> In the other cases, it's known from the receiver of the ::into call.
>
> * Assuming there is only one m() method, that is. If there's more than
> one, you just get the exact same error you get now.
>
> Obviously you know better than I whether this can work, but it
> would make ::into a whole lot nicer without requiring much more
> smarts from type inferencing. In particular, it doesn't require any
> global inferencing, only knowledge about the receiver, which it
> must have to even begin overload resolution.
>
> David
>
> P.S. ->
>
> Finally, on Tue, 29 May 2012 15:51:32 +0100, Richard Warburton<
> richard.warburton at gmail.com>  wrote:
>
>> I think it might well be useful to have sum operate over types
>> generally.  So if you have a Stream<T>  and can provide a Mapper<T,T>
>> then you can sumBy generally.  Obviously there are a variety of
>> mathematical structures that you might want to sum that aren't
>> primitives - for example a vector.  I'd probably expect that many
>> domain objects are the kind of things that you want to sum over as
>> well in some cases.  Presumably any domain object that's a commutative
>> monoid is safe for this kind of stuff?
>>
>> In these cases I think its safe for the signature of sumBy to be:
>>
>> <T>  T sumBy(Iterable<T>  values, Mapper<T,T>  summer)
>>
>> And people can provide their definition of the summer function,
>> instead of explicitly restricting the type of<T>  to things that you
>> can already syntactically do t1 + t2 on.
>>
>>
> You know, it would be really, really nice one day if arithmetic
> operators worked on BigInteger, or any ? extends Number.
>
> But that's a Coin for another time....
>



More information about the lambda-dev mailing list