An untyped parameter is one that is declared without a type. Delphi frequently uses untyped parameters when a function needs to be able to accept arguments of any type. To assign some type to those parameters would cause type-mismatch errors when a program tried to call the functions.
Often, a function that uses an untyped parameter should not really
accept just any parameter type. For example,
SysUtils.Supports
should only accept interface
variables, but the compiler will not object to variables of other types,
such as Integer
or string
.
Delphi has no middle-ground, though, for expressing that a parameter
should be a certain kind of type. Untyped parameters completely
circumvent the compiler’s type checker, so when using untyped
parameters, remember that type-safety is not a guarantee.
Below are some examples of functions that use untyped parameters.
System.Move
Listing 1
The Move
procedure
procedure Move(const Source; var Dest; Count: Integer);
The Move
procedure copies data from an arbitrary variable
into any other variable. It needs to accept sources and destinations of
all types, which means it cannot require any single type. The procedure
does not modify the value of the variable passed for
Source
, so that parameter’s declaration
uses const
instead of var
, which is the more common modifier for
untyped parameters.
SysUtils.Supports
Listing 2
Two (of several) declarations of the Supports
function
function Supports(const Instance: IInterface; const IID: TGUID; out Intf): Boolean; overload;
function Supports(const Instance: TObject; const IID: TGUID; out Intf): Boolean; overload;
The Supports
function determines whether a given object
implements a particular interface, optionally returning a reference to
the object’s interface. The third parameter, if present, needs to
be an interface-reference variable of the same type as the interface
represented by the GUID given in the second
parameter. (There is no way of expressing that requirement in code, so
the compiler cannot check it for you.) That can be any interface type, so
the Intf
parameter is declared as an untyped out
parameter.
The function uses out
instead of var
because the function disregards any value
already in the variable. Therefore, when you call Supports
,
the variable you pass for the third parameter should not contain
a valid interface reference. If it does, then Delphi will not reduce the
object’s reference count, and so the object might never get
freed.
SysUtils.FreeAndNil
Listing 3
Declaration of the FreeAndNil
function
procedure FreeAndNil(var Obj);
FreeAndNil
needs to accept variables of any
TObject
-descended type, and it also needs to be able to
assign new values to those variables. With a typed parameter, the
compiler would try to enforce type safety every time a program called the
function, and it would reject any call in which the actual parameter was
of a different type than the formal parameter. This is explained in more
detail in another article.
TApplication.CreateForm
Listing 4
Function heading for Application.CreateForm
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
The Delphi IDE generates calls to
Application.CreateForm
when it adds a form to a
project’s auto-create list. The first parameter is a class
reference for the form to be created, and the second parameter is the
variable that will receive a reference to the new object. See
“Why shouldn’t I call Application.CreateForm
?” for more
information.
As with Supports
, the types of
CreateForm
’s parameters need to correspond to each
other, but there is no way for the compiler to enforce that requirement.
The Reference
parameter must be of the same type
as the type passed to InstanceClass
.