inference of throws type parameters in SAMs

Peter Levart peter.levart at gmail.com
Wed Oct 31 17:07:14 PDT 2012


On 10/31/2012 10:48 PM, Maurizio Cimadamore wrote:
> On 31/10/12 20:51, Peter Levart wrote:
>> On 10/31/2012 06:48 PM, Maurizio Cimadamore wrote:
>>> On 31/10/12 17:37, Remi Forax wrote:
>>>> On 10/31/2012 06:20 PM, Maurizio Cimadamore wrote:
>>>>> On 31/10/12 17:04, Remi Forax wrote:
>>>>>> On 10/31/2012 03:53 PM, Dan Smith wrote:
>>>>>>> This is on the radar for inference. As you suggest, we would
>>>>>>> probably just choose RuntimeException in certain scenarios rather
>>>>>>> than using the upper bound.
>>>>>>>
>>>>>>> We have toyed with some more ambitious ideas for handling
>>>>>>> exceptions in lambda bodies, but those won't be part of Java 8.
>>>>>>>
>>>>>>> —Dan
>>>>>> yes, and my fear is that if we choose something different than 
>>>>>> Object
>>>>>> now (like RuntimeException)
>>>>>> we will not be able to change the inference algorithm in Java 9.
>>>>>> At least with Object as default, we know that currently the 
>>>>>> inference
>>>>>> fails so
>>>>>> we can provide a better one without creating incompatibilities.
>>>>> I think Object is never a problem - for this kind of issues to show
>>>>> up, the inference variable must appear in the throws clause, which
>>>>> means it should be at least <: Throwable.
>>>> yes, sorry,
>>>> s/Object/Throwable
>>>>
>>>> Choosing the bound of the unconstrained variable if the variable is
>>>> used in a throws in not the better choice,
>>>> but before we came with a better algorithm, it's a better choice than
>>>> RuntimeException because it doesn't
>>>> hamper the use of a better algorithm in the future.
>>> Yeah - I think that's kinda the choice ahead of us - on the one 
>>> hand, if
>>> we add exception transparency support in the future, it seems like this
>>> case should be handle as a result of that work; on the other hand,
>>> inferring RuntimeException could be a reasonable compromise, esp. given
>>> that the number of incompatibilities that will occur as a result of an
>>> inference upgrade would be pretty low (though it's true that when
>>> lambdas are available inference variables in the throws clause might
>>> become more common...).
>>>
>>> Maurizio
>> Can we elaborate about incompatibilities that will occur as a result 
>> of later inference upgrade?
>>
>> If I understood correctly, you are talking about inference upgrade 
>> that will happen after JDK8 and which will contain exception 
>> transparency support.
>>
>> So, unconstrained variable that is used in functional interface and 
>> appears only in throws declaration of the sole interface method. What 
>> incompatibilities can it cause if it is inferred now as 
>> RuntimeException as opposed to upper bound and in a later release as 
>> something more appropriate like Nothing? Can we imagine an example?
>
> An example would be along the following lines (admittedly convoluted):
>
> interface SAM<X extends Throwable> {
>     void m() throws X;
> }
>
> <Z> List<Z> m(SAM<Z> s) { ... }
>
> g(List<RuntimeException> l) { } //1
> g(Object o) { } //2
>
> g(m(()->{})); //resolves to (1) in JDK 8, resolves to (2) in JDK x+1, 
> x >= 8 ;-)
>
> Maurizio

Convoluted indeed. I thought about such scenarios and still can not 
imagine a situation where I would want to use a type variable in a 
combined mode - for throws declaration combined with the return type of 
a method like in above example which implies that exceptions that are 
first thrown are later caught and then returned.

Any such scenarios are inherently unsafe since any types of unchecked 
exceptions can always be legally thrown not just those that are declared 
or inferred - and they might not match the declared / inferred type.

So I would say that such scenarios would be rare or non-existent.

The other way around is possible and safe - exceptions generated or 
returned are later thrown. For example:

class Optional<T> {
    public<V extends Throwable> T orElseThrow(Factory<V> 
exceptionFactory) throws V;
    ...
}

But this usage does not suffer from the lack of constraints.

Regards, Peter

>
>>
>> Regards, Peter
>>
>>>>> Maurizio
>>>> Rémi
>>>>
>>>>>> Rémi
>>>>>>
>>>>>>> On Oct 30, 2012, at 10:18 AM, Peter Levart <peter.levart at gmail.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Hi all,
>>>>>>>>
>>>>>>>> I know this has been discussed before, but a long time has 
>>>>>>>> passed and
>>>>>>>> various inference algorithms have been tried in the meanwhile. 
>>>>>>>> So I
>>>>>>>> would like to ask whether current state is final. For example if I
>>>>>>>> have
>>>>>>>> a functional interface like the following:
>>>>>>>>
>>>>>>>> public interface ThrowingFactory<T, E extends Throwable> {
>>>>>>>>        T make() throws E;
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> And a "hypothetical" method:
>>>>>>>>
>>>>>>>> public interface Stream<T> {
>>>>>>>>        <E extends Throwable> T 
>>>>>>>> findFirstOrElse(ThrowingFactory<T, E>
>>>>>>>> other) throws E;
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> Then the following program compiles OK:
>>>>>>>>
>>>>>>>>        public static void main(String... args) throws IOException
>>>>>>>>        {
>>>>>>>>            Stream<String> stream = null;
>>>>>>>>
>>>>>>>>            String first = stream.findFirstOrElse(() -> {throw new
>>>>>>>> IOException();});
>>>>>>>>        }
>>>>>>>>
>>>>>>>>
>>>>>>>> Which indicates that the inference algorithm does it's job 
>>>>>>>> correctly.
>>>>>>>> But the following program:
>>>>>>>>
>>>>>>>>        public static void main(String... args)
>>>>>>>>        {
>>>>>>>>            MyStream<String> stream = null;
>>>>>>>>
>>>>>>>>            String first = stream.findFirstOrElse(() -> "NO 
>>>>>>>> VALUE");
>>>>>>>>        }
>>>>>>>>
>>>>>>>>
>>>>>>>> Triggers the compilation failure:
>>>>>>>>
>>>>>>>> error: unreported exception Throwable; must be caught or declared
>>>>>>>> to be
>>>>>>>> thrown
>>>>>>>>            String first = stream.findFirstOrElse(() -> "NO 
>>>>>>>> VALUE");
>>>>>>>>
>>>>>>>>
>>>>>>>> Regards, Peter
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> P.S. If this worked, the controversial TypeThatMustNotBeNamed<T>
>>>>>>>> which
>>>>>>>> is used as return type of 3 Stream methods could be replaced with
>>>>>>>> 3*3=9
>>>>>>>> Stream methods that would more or less fit the main purpose of 
>>>>>>>> being
>>>>>>>> fluent. For example, current Stream.findFirst() would expand to:
>>>>>>>>
>>>>>>>> public interface Stream<T> {
>>>>>>>>        T findFirst() throws NoSuchElementException;
>>>>>>>>        T findFirstOrElse(T other);
>>>>>>>>        <E extends Throwable> T 
>>>>>>>> findFirstOrElse(ThrowingFactory<T, E>
>>>>>>>> other) throws E;
>>>>>>>> }
>>>>>>>>
>>>>>>>> Is this to much methods?
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>
>>
>



More information about the lambda-dev mailing list