Consider the following program:
program IntegerOverloads;
{$APPTYPE CONSOLE}
procedure WordOrCardinal(Value: Word); overload;
begin
Writeln('Word');
end;
procedure WordOrCardinal(Value: Cardinal); overload;
begin
Writeln('Cardinal');
end;
procedure SmallintOrInteger(Value: Smallint); overload;
begin
Writeln('Smallint');
end;
procedure SmallintOrInteger(Value: Integer); overload;
begin
Writeln('Integer');
end;
procedure ShortintOrSmallint(Value: Shortint); overload;
begin
Writeln('Shortint');
end;
procedure ShortintOrSmallint(Value: Smallint); overload;
begin
Writeln('Smallint');
end;
procedure Main;
var
_integer: Integer;
_cardinal: Cardinal;
_word: Word;
begin
WordOrCardinal(_Integer);
SmallintOrInteger(_cardinal);
ShortintOrSmallint(_word);
end;
begin
Main;
Readln;
end.
The output when compiled by XE2 is:
Cardinal
Integer
Smallint
The output when compiled by Delphi 6 is:
Word
Smallint
Shortint
The documentation states (emphasis mine):
You can pass to an overloaded routine parameters that are not identical in type with those in any of the routine's declarations, but that are assignment-compatible with the parameters in more than one declaration. This happens most frequently when a routine is overloaded with different integer types or different real types - for example:
procedure Store(X: Longint); overload; procedure Store(X: Shortint); overload;In these cases, when it is possible to do so without ambiguity, the compiler invokes the routine whose parameters are of the type with the smallest range that accommodates the actual parameters in the call.
But that does seem to apply here. None of the procedure calls in the example code accept a type that accommodates the actual parameters in the call.
I cannot find any documentation that describes what rule the compiler follows. Can anyone point me to such documentation?
This question was prompted by the following articles:
- ReverseBytes()
- ZeroConf/Bonjour Code that works in Delphi 7 not working in 2009
- What's in a Word ... ?
Update
Prompted by Ken White's comments, I wrote another program to illustrate some more oddities:
program IntegerOverloadsPart2;
{$APPTYPE CONSOLE}
procedure Test(Value: Byte); overload;
begin
Writeln('Byte');
end;
procedure Test(Value: Word); overload;
begin
Writeln('Word');
end;
procedure Test(Value: Cardinal); overload;
begin
Writeln('Cardinal');
end;
procedure Test(Value: Uint64); overload;
begin
Writeln('Uint64');
end;
procedure Main;
var
_byte: Byte;
_shortint: Shortint;
_word: Word;
_smallint: Smallint;
_cardinal: Cardinal;
_integer: Integer;
_uint64: UInt64;
_int64: Int64;
begin
Writeln('Unsigned variables passed as parameters:');
Test(_byte);
Test(_word);
Test(_cardinal);
Test(_uint64);
Writeln;
Writeln('Signed variables passed as parameters:');
Test(_shortint);
Test(_smallint);
Test(_integer);
Test(_int64);
end;
begin
Main;
Readln;
end.
When compiled by XE2 the output is:
Unsigned variables passed as parameters:
Byte
Word
Cardinal
Uint64
Signed variables passed as parameters:
Uint64
Uint64
Uint64
Uint64
On Delphi 6 I have to remove the UInt64 overload since that type does not exist on Delphi 6 the output is:
Unsigned variables passed as parameters:
Byte
Word
Cardinal
Signed variables passed as parameters:
Byte
Byte
Byte
Again neither behaviour looks consistent with the statement that:
In these cases, when it is possible to do so without ambiguity, the compiler invokes the routine whose parameters are of the type with the smallest range that accommodates the actual parameters in the call.
_worddoes not change it's size fromSmallInt, and a very large value leaves it unchanged as well.) I wonder if this is related to changes made for 32/64 bit support? - Ken WhiteWordOrCardinalwith anInteger, which is 32-bit, should call theCardinalversion barring any compile-time information about the value, as a 32-bitIntegercan't be presumed to fit into a 16-bitWord. The same applies toShortintOrSmallInt(_word), where a 16-bitWordcan't possibly be assumed to fit into an 8-bitShortInt, so it resolves toSmallIntinstead. It may result in a runtime range check or overflow exception, but at compile time there's no value to consider. Am I missing something? - Ken White