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

Reply via email to