<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<div class="moz-cite-prefix">Am 06.04.2021 um 17:45 schrieb Ryan
Joseph via fpc-devel:<br>
</div>
<blockquote type="cite"
cite="mid:1ABFA653-B5C7-411F-AF92-E0C9E46E72D7@gmail.com">
<pre class="moz-quote-pre" wrap="">Finally some movement is happening on implicit function specialization and I'm almost finished now except some questions about precedence have been raised again. Initially I thought we decided on non-generic functions taking precedence in the case of *any* name collisions (the original thread <a class="moz-txt-link-freetext" href="https://lists.freepascal.org/pipermail/fpc-pascal/2018-December/055225.html">https://lists.freepascal.org/pipermail/fpc-pascal/2018-December/055225.html</a>) but Sven is saying now that this isn't the case (see the remarks on the bug report <a class="moz-txt-link-freetext" href="https://bugs.freepascal.org/view.php?id=35261">https://bugs.freepascal.org/view.php?id=35261</a>). I'm asking this here not to go over Svens head but in hopes to get some answers quicker (it can take us weeks sometimes to round trip even simple questions).
Currently what I implemented is that in the case below non-generic Test() will take precedence even though Test<T> could be specialized and indeed even comes after. My questions:
1) What is required for Delphi compatibility? I never used Delphi and I thought we decided this initially for Delphi compatibility. Of course we can make a Delphi mode only option if we need to.
2) Svens final remarks on the bug tracker are "Right now your code will pick the existing String overload even if specializing the generic might be the better choice. If the user really wants the String one (or if the specializing the generic does not work) the user can still force the String overload by casting the parameter to a String.". I'm confused about this because Test(String) and Test<String> are both identical and thus I don't see what is the "better choice".
Personally I feel like we should fallback to the non-generic function as a way to resolve ambiguity but I can also see why Test<T> should take precedence simply because it comes after Test().</pre>
</blockquote>
<br>
In the example you posted below, I agree with you, but that is not
what I said. Look at my example again:<br>
<br>
=== code begin ===<br>
<br>
<pre>program timplicitspez;
{$mode objfpc}{$H+}
{$modeswitch IMPLICITFUNCTIONSPECIALIZATION}
function Test(const aStr: String): LongInt;
begin
Result := 1;
end;
generic function Test<T>(aT: T): LongInt;
begin
Result := 2;
end;
operator := (aArg: LongInt): String;
begin
{ potentially expensive conversion }
Result := '';
end;
begin
Writeln(Test('Hello World'));
Writeln(Test(42));
end.
</pre>
=== code end ===<br>
<br>
The important part here is the operator overload. If the generic
function would not exist then the compiler would simply call the
operator overload to convert the 42 to a String and call the
function with the string overload. While in this example the
conversion is essential a no-op in reality it might be more complex
and expensive thus it might be better to use the implicit
specialization of the 42 as is (in this case it would be a LongInt I
think). Right now there is no possibility to enforce the use of the
implicit specialization. <br>
<br>
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.<br>
<br>
And to pick the non-generic one can do this in the above example:
Test(String(42)), because here the type your implicit specialization
code will receive will be String already and thus the generic vs.
non-generic check will catch it and prefer the non-generic one.<br>
<br>
Also Delphi agrees with me:<br>
<br>
=== code begin ===<br>
<br>
program timplspez;<br>
<br>
{$APPTYPE CONSOLE}<br>
<br>
uses<br>
SysUtils;<br>
<br>
type<br>
TFoo = record<br>
f: LongInt;<br>
class operator Implicit(aArg: LongInt): TFoo;<br>
end;<br>
<br>
TTest = record<br>
class function Test(aArg: TFoo): LongInt; overload; static;<br>
class function Test<T>(aArg: T): LongInt; overload;
static;<br>
end;<br>
<br>
class operator TFoo.Implicit(aArg: LongInt): TFoo;<br>
begin<br>
Result.f := aArg;<br>
end;<br>
<br>
class function TTest.Test(aArg: TFoo): LongInt;<br>
begin<br>
Result := 1;<br>
end;<br>
<br>
class function TTest.Test<T>(aArg: T): LongInt;<br>
begin<br>
Result := 2;<br>
end;<br>
<br>
var<br>
f: TFoo;<br>
begin<br>
f := 21;<br>
Writeln(TTest.Test(f));<br>
Writeln(TTest.Test(42));<br>
Writeln(TTest.Test(TFoo(42)));<br>
Readln;<br>
end.<br>
<br>
=== code end ===<br>
<br>
=== output begin ===<br>
<br>
1<br>
2<br>
1<br>
<br>
=== output end ===<br>
<br>
This should answer both your points, cause they're related.<br>
<br>
Regards,<br>
Sven<br>
</body>
</html>