The hint looks like this:
H2443 Inline function 'TFDParam.SetAsLargeInt' has not been expanded
because unit 'FireDAC.Stan.Param' is not specified in USES list
It is only a hint. The code compiles and runs correctly. The compiler is telling you that a
function marked inline was called as an ordinary function instead of having its
body copied into your code, and it names the unit you need to add to make the copy
possible.
When a function is marked inline, the compiler tries to replace each call with
the body of the function. That body may use types, functions or constants from other units. To
copy the body into your unit, the compiler must be able to resolve every one of those names
from your unit - which means each unit the body depends on has to be in your unit's
uses clause. If one is missing, the compiler falls back to a normal call and
issues H2443 naming the missing unit.
The usual FireDAC case: you use TFDQuery from FireDAC.Comp.Client,
but the parameter class TFDParam, whose property setters are inline, is declared in
FireDAC.Stan.Param.
unit Params_Without;
interface
uses
FireDAC.Comp.Client;
procedure FillParams(AQuery: TFDQuery; const ACount: Integer);
implementation
procedure FillParams(AQuery: TFDQuery; const ACount: Integer);
var
I: Integer;
begin
for I := 1 to ACount do
begin
AQuery.Params[0].AsLargeInt := I; // H2443 here
AQuery.Params[1].AsString := 'Name'; // and here
end;
end;
end.
Delphi 13 gives four hints for those two lines - not two:
H2443 Inline function 'TFDParams.GetItem' has not been expanded because unit 'System.Classes' is not specified in USES list
H2443 Inline function 'TFDParam.SetAsLargeInt' has not been expanded because unit 'FireDAC.Stan.Param' is not specified in USES list
H2443 Inline function 'TFDParams.GetItem' has not been expanded because unit 'System.Classes' is not specified in USES list
H2443 Inline function 'TFDParam.SetAsString' has not been expanded because unit 'FireDAC.Stan.Param' is not specified in USES list
Params[0] goes through the inline getter TFDParams.GetItem, which
needs System.Classes; the setters need FireDAC.Stan.Param. Code that uses
ParamByName instead of Params[n] only gets the second kind.
Add the unit the hint names. It can go in the implementation section's
uses clause if nothing in the interface needs it.
unit Params_With;
interface
uses
System.Classes, FireDAC.Stan.Param, FireDAC.Comp.Client;
procedure FillParams(AQuery: TFDQuery; const ACount: Integer);
implementation
procedure FillParams(AQuery: TFDQuery; const ACount: Integer);
var
I: Integer;
begin
for I := 1 to ACount do
begin
AQuery.Params[0].AsLargeInt := I;
AQuery.Params[1].AsString := 'Name';
end;
end;
end.
No hints. Note that the hint names one unit at a time: after you add one, a second hint can
appear for another inline function on the same line, as with GetItem above. Build
again until they are all gone.
The difference is the cost of one call per use - small, and only noticeable in tight loops. Both units above were compiled with optimisation on (Win64) and timed setting the two parameters 10,000,000 times each, five runs of 2,000,000:
About 4%. For most code that is not worth worrying about, but the fix is one line in the uses clause, and clearing the hints means the ones that matter are not lost among them.
The same rule applies to your own code, and it affects the units that call yours. This
function uses Power from System.Math:
unit Shapes;
interface
function CircleArea(const ARadius: Double): Double; inline;
implementation
uses
System.Math;
function CircleArea(const ARadius: Double): Double;
begin
Result := Pi * Power(ARadius, 2);
end;
end.
Any unit that calls it without using System.Math itself gets the hint:
unit Area_Report;
interface
function TotalArea(const ACount: Integer): Double;
implementation
uses
Shapes;
function TotalArea(const ACount: Integer): Double;
var
I: Integer;
begin
Result := 0;
for I := 1 to ACount do
Result := Result + CircleArea(I); // H2443 - needs System.Math
end;
end.
Moving System.Math to the interface uses clause of Shapes does
not help. That was tested: the hint still appears in Area_Report, because only the
calling unit's own uses clause counts. The choices are:
System and the unit the
function is declared in. Pi * ARadius * ARadius would have no dependency at all
and always expand.inline. A function that calls something like
Power gains very little from being inlined anyway.uses clause,
implementation section is fine. Repeat until no H2443 is left.
Please chip in if helpful