groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <blackd...@gmx.org>
Subject Re: About type inference of method return value
Date Thu, 06 Sep 2018 09:37:45 GMT


Am 06.09.2018 um 02:23 schrieb MG:
> Hi Jochen,
> 
> but in what sense is any of these examples confusing for the user ? Type 
> inference is not magic, and it can quickyl become a hard mathematical 
> problem (https://en.wikipedia.org/wiki/Type_inference).

And you as user do not have to understand the inferred type? I would 
like to be able to do that without a mathematical degree.

> But in all that 
> cases, we should just fall back to Object or throw. I don't know 
> Daniel's intentions, but for me type inference for methods (same as for 
> fields/variables) should only be used for simple, obvious cases, not for 
> complex ones (eveb if these are of course the only interesting 
> intellectual challnge ;-) ).

If it is only for simple cases it will always strike the user as a not 
very powerful system and the user might be wondering what this inference 
for the return type actually is... unless we call it "simple return type 
inference" of course.

[...]
>>
>>> private foo() {
>>>   if (something) {
>>>      return x // of class X
>>>   } else {
>>>      return y // of class Y
>>>   }
>>> }
>>
>> if X and Y implement the interfaces Foo and Bar the common super type 
>> would be something like Object+Foo+Bar, which cannot be an actual 
>> return type, because the Java type system cannot properly express that 
>> type. Which is it then? Object, or Foo or Bar? 
> 
> Intuitively I would not infer on interfaces, but only classes. In 
> practice I would expect X and Y to have a common superclass that is not 
> Object; otherwise infer Object.

if we keep it simple we fail here, which means compilation error

>> And if you think this problem is small, you have to consider this one 
>> here as well:
>>
>>> private foo() {
>>>   def ret
>>>   if (something) {
>>>      ret = x // of class X
>>>   } else {
>>>      ret = y // of class Y
>>>   }
>>>   return ret
>>> }
>>
>> Same problem as before obviously, just showing that using local 
>> variables makes it even worse.
> 
> Infer Object - if you use Object for the return variable type, this is 
> what you should expect...

If I had use X or Y it would have failed compilation. That is my point here.

>> And how about this one?
>>
>>> private f(List<X> l) {   if (l.size()==1) {
>>>     return l[0]
>>>   } else {
>>>     return f(l.tail())
>>>   }
>>> }
>>
>> for me it is obvious the return type is X, but a compiler must be able 
>> to see through the recursive call and it must see that it is a 
>> recursive call.
> 
> Too complex => infer Object

Too complex => fail compilation!

[...]
>> Or let us say there is also g(Object):Object and let us assume we 
>> delete g(X):X. Then inferring the type above successfully means 
>> obviously to let f return Object. The change will go unnoticed in f 
>> and cause secondary errors in callers of f. In the worst case even 
>> quite far away from the callsite itself.
> 
> I do not follow: What secondary errors would that be ? How would they 
> differ from errors that occur when the user explicitely supplies Object 
> as return type ?


lets say you have

def g() {
  f()+1
}

int b = g()


let us say that the type for f changed from int to long, then g() will 
still compile, but now it will also return long instead of int. This 
will cause int b = g() to fail compilation because of loss of precision 
from long to int. And to fix this you will have to fix not the 
assignment, not g, but f.


bye Jochen

Mime
View raw message