Does not pertinent to applicability mean not used?
Zhong Yu
zhong.j.yu at gmail.com
Wed Apr 30 01:44:32 UTC 2014
If an argument is not pertinent to applicability, it is ignored during
the applicability test. Other than that, I don't see what effect it
has.
Consider this simple code
void test(Stream<String> ss)
{
ss.map( s->Integer.parseInt(s) );
}
The implicit lambda expression is not pertinent to applicability; it
does not prevent the compiler from inferring that the invocation
returns Stream<Integer>
On Tue, Apr 29, 2014 at 5:52 PM, Timo Kinnunen <timo.kinnunen at gmail.com> wrote:
> Hi,
>
> Re: “I would expect the code is valid. We expect that something like this
>
> should work:
>
> Function<Integer, Function<Integer, Integer>> f = x->y->x+y;
>
> i.e. the target type propagates inwards, y is determined to be Integer.”
>
> As far as I know, and this should be taken with a huge grain of salt, the
> issue isn’t propagating inwards per se. Indeed, both compilers determine the
> type of the variable “item” to be String in both versions of the code,
> otherwise the string concatenation of “item” and “s” would fail first.
>
> Rather, the issue is what happens after that. Do the constraints from the
> lambda whose target type is not pertinent to the applicability of calling
> map() propagate back outwards to the receiver of .collect()? ECJ’s reading
> of the specification says they do not, Javac’s reading of the specification
> says they do. Which one is correct?
>
> The same issue can be observed with inexact method references, too, the code
> example just ends up being longer:
>
> import java.util.List;
> import java.util.Map;
> import java.util.stream.Collector;
> import java.util.stream.Stream;
>
> abstract class Entry2<K, V> implements Map.Entry<K, V> {
> abstract <N> Entry2<N, V> replaceKey(N value);
> }
>
> abstract class DoesNotPertinentMeanNotUsed2 {
>
> abstract Stream<String> entryToStream(Entry2<List<String>, String> p);
>
> Stream<Entry2<List<String>, String>> s2;
>
> Collector<Entry2<String, String>, ?, Map<String, List<String>>> c2;
>
> Map<String, List<String>> methodReferenceVersionWithError() {
> //The method collect(Collector<? super Object,A,R>) in the type
> Stream<Object> is not applicable
> //for the arguments (Collector<Entry2<String,String>,capture#1-of
> ?,Map<String,List<String>>>)
> return s2.flatMap(p -> entryToStream(p).map(p::replaceKey)).collect(c2);
> }
>
> Map<String, List<String>> lambdaVersionWithError() {
> //The method collect(Collector<? super Object,A,R>) in the type
> Stream<Object> is not applicable
> //for the arguments (Collector<Entry2<String,String>,capture#2-of
> ?,Map<String,List<String>>>)
> return s2.flatMap(p -> entryToStream(p).map(string ->
> p.replaceKey(string))).collect(c2);
> }
>
> Map<String, List<String>> versionWithoutError() {
> return s2.flatMap(p -> entryToStream(p).map((String string) ->
> p.replaceKey(string))).collect(c2);
> }
> }
>
> Hopefully this shows exactly where the difference is.
>
>
>
>
> --
> Have a nice day,
> Timo.
>
> Sent from Windows Mail
>
> From: Zhong Yu
> Sent: Wednesday, April 30, 2014 01:36
> To: Timo Kinnunen
> Cc: lambda-dev at openjdk.java.net
>
> On Tue, Apr 29, 2014 at 3:47 PM, Timo Kinnunen <timo.kinnunen at gmail.com>
> wrote:
>> Hi,
>>
>>
>> This code shows a difference in type inference between ECJ and Javac:
>>
>>
>> package differences.lost.typing;
>>
>> import java.util.List;
>>
>> import java.util.Map;
>>
>> import java.util.stream.Collector;
>>
>> import java.util.stream.Stream;
>>
>>
>> class DoesNotPertinentMeanNotUsed {
>>
>> Stream<Stream<String>> s;
>>
>> Collector<String, ?, Map<String, List<String>>> c;
>>
>>
>> Map<String, List<String>> versionWithError() {
>>
>> return s.flatMap(t -> t.map(item -> t + item)).collect(c);
>>
>> }
>>
>> Map<String, List<String>> versionWithoutError() {
>>
>> return s.flatMap(t -> t.map((String item) -> t + item)).collect(c);
>>
>> }
>>
>> }
>>
>>
>> Javac compiles both versions without error messages, ECJ infers the return
>> type of the .flatMap() method call in the first version to be something like
>> Stream<?> which results in a compile error in the call to .collect().
>>
>>
>> In the versionWithError, the inner lambda expression’s (item -> t + item)
>> type is inexact which means it’s not pertinent to applicability for the call
>> to .map(). I am told this is means it doesn’t affect the inferred return
>> type of .map() method call, leaving it unknown, thus making this code
>> invalid, correctly.
>
> I would expect the code is valid. We expect that something like this
> should work:
>
> Function<Integer, Function<Integer, Integer>> f = x->y->x+y;
>
> i.e. the target type propagates inwards, y is determined to be Integer.
>
>>
>>
>> In the versionWithoutError, the inner lambda expression ((String) item ->
>> t + item) can be pertinent to applicability so it’s type constraints are
>> considered, leading eventually to the type Stream<String> coming out at the
>> other end, and the code being valid.
>>
>>
>> Which compiler is correct, and why?
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> --
>> Have a nice day,
>> Timo.
>>
>> Sent from Windows Mail
>>
More information about the lambda-dev
mailing list