[fpc-devel] Implicit function specialization precedence

Sven Barth pascaldragon at googlemail.com
Wed Apr 7 07:34:20 CEST 2021

Am 06.04.2021 um 22:47 schrieb Ryan Joseph via fpc-devel:
>> On Apr 6, 2021, at 12:57 PM, Sven Barth <pascaldragon at googlemail.com> wrote:
>> In this specific case the two functions also are *not* ambigous, because for the non-generic Test the parameter requires an implicit conversion, but the implicit specialization does not. For example if there would be a "Test(aArg: LongInt)" instead of the generic the compiler would pick that instead of the string one. So if you move the check for generic vs. non-generic to the end of is_better_candidate all the other rules to determine this will take precedence.
> So the root of the problem is that we have no way to choose the generic function via explicit casting? That makes sense and presumably I can use the final result of is_better_candidate to determine this?

You simply need to put your check for generic vs. not-generic after the 
check for ordinal_distance inside is_better_candidate instead of at the 
start of the function.

>   In your example:
> Writeln(Test('Hello World'));			// is_better_candidate res = -1
> Writeln(Test(42));					// is_better_candidate res = 1
> Writeln(Test(String(42)));			// is_better_candidate res = -1
> I'm struggling to see how the operator influenced the result. Res is -1 in both cases so how do we know which Test we want to call?

The compiler is free to use implicit operator overloads when determining 
the overload to pick.

When the compiler sees the first call to Test it will have the 
non-generic Test(String) in its candidate list as well as 
Test<String>(String) due to the implicit specialization. Here it will 
use the non-generic one.

In the second case the compiler will have the non-generic Test(String) 
due to the implicit operator as well as Test<LongInt>(LongInt) due to 
the implicit specialization. Here it will pick the generic one, because 
a call without a type conversion is considered better.

In the third case the will will contain Test(String) as well as 
Test<String>(String) due to the parameter being explicitely casted to 
String with the compiler again picking the non-generic one.

Without the explicit cast by the user the compiler would have picked the 
Test<LongInt>, but using a cast to the type of non-generic function one 
is able to enforce the non-generic function (for example to avoid an 
error during specialization if the Test<> function would not be able to 
handle the LongInt type).


More information about the fpc-devel mailing list