Full disclosure: I work with Jason
I think this is one of those sharp corners of the language, which is to say I know it is like it is for a good reason, but it's still something easy to overlook that can bite you if you aren't careful.
I will say, I'm glad the language is resilient to code changes, in the sense that adding a default value to that second parameter at a later point in time would not change the semantics of any call sites that had been using the first method. That's certainly why the compiler uses the "most specific" rule to resolve ambiguity.
The one place where this can "bite" you is in the following scenario:
Say you're implementing a protocol or inheriting from a class that defines and implements doSomething(with:)
. You then write your own method doSomething(with:andMaybe:)
but decide to add that default parameter for some good reason. You then go to use your method somewhere, not realizing you're actually calling the inherited form.
This is the exact scenario Jason found himself in and, I think, is why this topic has been brought up a few times before.
A warning would certainly be helpful in this scenario, but it would be obnoxious in others, so finding a reasonable way to silence it is critical. Here's some scenarios and imperfect solutions:
- If you intended to call the arity-2 function, silencing the warning is trivial because you can simply add the second parameter to your call. The fix-it could even insert the default value for you. It's annoying to have to specify what should be a default, but there's just no other way to do it and it's the right move, even without the warning.
- Removing the default value would also be a sensible fix-it, but could only apply if you own that code. If you only happen to own the short-form method, there's nothing reasonable you could do except rename it.
- Other more dramatic changes like changing the parameter or function names could be recommended, but I'm not sure the compiler would want to do that since it wouldn't have any way to generate a recommended name. It's not like the near-miss protocol conformance scenario — there's concrete to compare against. I suppose it could just point you to the func definitions and say "consider renaming".
One way to silence the warning comes to mind which would work in all scenarios. A fix-it could suggest you use the fully-qualified name as an unapplied reference. For example:
Did you mean?
doSomething(with:)("abc")
doSomething(with:andMaybe:)("abc")
I admit this is truly strange usage of function calls, but it's perfectly valid and does what you'd expect. Typically you'd only use the unapplied reference when you want to, say, pass one of the functions as a parameter — point-free style.
This is the only way to remove all ambiguity, but considering how strange it is I dunno if this is the right move.
But then again, since this scenario is rare enough in the first place, maybe using a rarely-used feature is appropriate!
It would be nice to highlight this surprising corner-case for people. Even veterans can trip over this ambiguity from time to time.