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 Wed, 05 Sep 2018 21:03:26 GMT
On 05.09.2018 14:36, mg wrote:
> I agree with Daniel here, I also don't see how this could be confusing (?).
> 
> Even if the inference mechanism falls back to inferring Object, the user 
> will just get an "cannot call dadadam on Object" or such compile error - 
> which should immediately leave to the conclusion that the type needs to 
> be given explicitely in this case...
> 
> Does anyone have an example that shows such a malign/confusing type 
> deduction case ?

Let's start easy

> private foo() {
>   return new SomeMarkerInterface(){
>     def x() {1}
>   }
> }

is the return type here SomeMarkerInterface or XYZ$1? Can I do foo().x()?

> 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? 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.

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.

> private f(List<X> l) { 
>   if (l.size()==1) {
>     return g(l[0])
>   } else {
>     return g(f(l.tail()))
>   }
> }
> private g(X x){x}
> private g(List<X> l){l}


here it gets even more complicated... g(l[0]) is easy, that will return 
X, since l[0] will return X causing a call to g(X):X. But since we 
currently infer f, we cannot simply know what f(l.tail()) will be, thus 
we cannot easily know if we call here g(X):X or g(List<X>):List<X>.

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.

Wanting more?

> private f(List<X> l) { 
>   if (l.size()==1) {
>     return l[0]
>   } else {
>     return g(l.tail())
>   }
> }
> private g(List<X> l){f(l)}

to know the return type of f I need to know the return type of g, for 
which I need to know the return type of f... global type inference could 
solve such problems, but makes about everything else more complicated

bye Jochen


Mime
View raw message