Overload resolution chooses type that's invalid, too general or not at all
daniel.smith at oracle.com
Mon Jan 13 14:12:04 PST 2014
On Jan 10, 2014, at 4:05 AM, Timo Kinnunen <timo.kinnunen at gmail.com> wrote:
> In the case where the difference between two target types is only that one
> of them has a generic throws declaration, this leads to ambiguity even when
> choosing the wrong one would be a compile error.
> This seems to be working as specified, with the goal to make the result
> more stable and predictable, but I would argue the actual result is just
> the opposite. Why not try each candidate in turn and choose the one that
> throws the least?
"Do exactly what I want" and "be stable and predictable" are often in tension when the compiler is asked to infer something.
You're right that the treatment of exceptions thrown by a lambda body in overload resolution is by design, with the intent that ambiguity errors will prompt the user to be more explicit about what he wants (and prompt API designers to avoid these subtle overloads).
I know what you want is to define two identical methods that simply vary in the exceptions thrown. The problem is that, for all the compiler knows, the two methods do dramatically different things, and the compiler is interested in minimizing the risk of accidentally getting the wrong behavior.
(What you mean, by the way, is "choose the one that throws the least ***but still declares all the exceptions thrown by the lambda body***".)
> I have found a workaround. By making some small artificial changes (notice
> a pattern?) to one method that makes its signature less readable I can
> affect changes in which rounds each method participates. This allows things
> to compile but I lose some useful information about which lambdas actually
> don't throw exceptions. I have found a lot of variations to choose from
> but not the one that produces the optimal result so far.
The simplest solution is to simply give the methods different names.
> I'd like the compiler to choose the optimal method automatically, because
> it knows the types better than I do.
The problem is that the compiler doesn't know whether you really mean to throw an exception, or whether you intend to catch it but you forgot. And it doesn't know whether you really meant to change the program's behavior when you commented out a line that happened to throw an exception.
> Absent that, I'd like it to give each
> method its due consideration, because that's why I added the overloads in
> the first place. Absent that, I'd like some API for saying which order the
> overloaded methods should be tried. And absent that, I'd like to have some
> official documentation on how to correctly target methods to a particular
> round of resolution.
As an API designer, you make one method have priority over another by either i) making it more specific than another for expected inputs; or ii) making it applicable in an earlier phase for expected inputs. I acknowledge that you're looking for something more; it's not clear that this is a general enough problem to prompt language changes.
But in any case, I don't see how this helps. If you make the method that has a non-exception-throwing functional interface parameter more specific than the method that has an exception-throwing functional interface parameter, you're just going to get compiler errors whenever you have any exceptions. Both methods will always be applicable, because exceptions thrown by a lambda body do not influence method applicability.
May I suggest that what you really mean to say is this: the language doesn't handle exception transparency for lambda expressions very well? If so, then yes, we know, and have some ideas about how to address that problem, preferably entirely sidestepping overloading and generics.
More information about the lambda-dev