Wednesday, December 01, 2004

Delphi Inline functions and your Uses clause

Back on More Coding Peeves someone asked me about the warning:

'AnsiSameText' has not been expanded because unit 'Windows' is not specified in USES list
I looked in SysUtils and AnsiSameText is declared as:
function AnsiSameText(const S1, S2: string): Boolean; inline;

So it is in fact an Inline function. The help for the warning explains:

This situation may occur if an inline function refers to a type in a unit that is not explicitly used by the function's unit. For example, this may happen if the function uses inherited to refer to methods inherited from a distant ancestor, and that ancestor's unit is not explicitly specified in the uses list of the function's unit.

If the inline function's code is to be expanded, then the unit that calls the function must explicitly use the unit where the ancestor type is exposed.

Lets take a look at what exactly function inlining is. When you call an inline function what happens at the compiler level is that the actual code of function is expanded at the location of the call instead of a call being made to a function. A call translates into variables being pushed onto the stack, a jump being made, variables being popped off the stack, etc. So if there isn't a lot of code in a function then it makes sense to inline it.

AnsiSameText calls AnsiCompareText which is also Inline. If your are running under Windows then AnsiCompareText calls CompareString which is in Windows.pas. When these inline functions are expanded your call to AnsiSameText is actually becomes a call to CompareString from your unit.

Julian Bucknall has a rant about how the fact that Inline is only a hint to the compiler that your function is inlined. This is why inlining is only a hint. Your unit may not be able to have the expanded code in it because of a type or call that is declared in another unit that your unit does not use.

What does all this mean to you and your "No Hints or Warnings Policy"? Since Windows is used in the SysUtils unit you do not gain anything by excluding it from your uses clause. So put Windows back at the beginning of your uses clause and the warning will go away, and your program should not be any different. If you want to be cross platform compatible then do something like:

{$IFDEF MSWINDOWS}
Windows,
{$ENDIF}
{$IFDEF LINUX}
Types,
Libc,
{$ENDIF}

Excluding the Windows unit from your uses clause is important if you are going for cross platform compatibility, but if you are trying to reduce code bloat then you aren't accomplishing anything since SysUtils calls it directly, in fact that uses clause is directly from its uses clause.

2 comments:

Anonymous said...

Thas someone was me (Remco) ;-)

I do agree with you that this is a fix to prevent inline hints from occurring, but i don't like it that the responsibillity for using the {$IFDEF WINDOWS} is now forced upon us 'mere' users by the usage of the new inline keyword.

My policy of "no hints, no warnings" is as fundamental as my "do not use not used units" policy.

And i must object to using {$IFDEF WINDOWS} constructs throughout code that is not platform specific / dependant!

Is there no other way out?

Remco

unused said...

Remco,

Interesting that you refer to yourself as a 'mere' user. In my opinion, if you are a software developer, especially one who is savvy enough to adopt "no hints, no warnings" and "no unused units" policies, then you are no longer a 'mere user' but a power developer. Give yourself more credit.

I do understand your irritation with using compiler directives though. I don't think anyone likes them specifically.

I made a new post about the {$INLINE compiler directive. Maybe it will help you out.

-Jim