Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to safely bypass Delphi Error: "types of formal and actual parameters must be identical"

Tags:

delphi

I need a way to write a generic procedure to act upon an object type or any of its descendants.

My first attempt was to declare

procedure TotalDestroy(var obj:TMyObject);

but when using it with a descendant object

type TMyNewerObject = class(TMyObject);
var someNewerObject: TMyNewerObject;

TotalDestroy(someNewerObject);

I get the infamous error "types of formal and actual parameters must be identical"

So, while strugling to find a solution, I looked at the source code of Delphi system FreeAndNil procedure. And I found this awesome declaration, along with this astonishing comment

{ FreeAndNil frees the given TObject instance and 
  sets the variable reference to nil.  
  Be careful to only pass TObjects to this routine. }

procedure FreeAndNil(var Obj);

It avoids the type checking error, but it uses no safety net.

My question is ... is there any safe way to check the type of an untyped var parameter?

or in other words, can you improve this Delphi source code so that the warning would not be needed?

procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;
like image 773
PA. Avatar asked Jan 12 '10 19:01

PA.


1 Answers

Let's examine what you want to do.

You want to call a method that takes X, passing in an object of type Y, where Y is a descendant of X. The snag, the parameter is a "var" parameter.

Let's analyze what you could do if that was possible.

type
    TBase = class
    end;
    TDescendant = class(TBase)
    end;

procedure Fiddle(var x: TBase);
begin
    x := TDescendant.Create;
end;

type
    TOtherDescendant = class(TBase)
    end;

var a: TOtherDescendant;
a := TOtherDescendant.Create;
Fiddle(a);

Uh-oh, now a no longer contains an instance of TOtherDescendant, it contains an instance of TDescendant. That probably comes as a surprise to the code that follows the call.

You must not only consider what you intend to do with the syntax you propose, but effectively what you could do with the syntax.

You should read Eric Lipperts excellent blog post about similar issues in .NET, found here: Why do ref and out parameters not allow type variation?.

like image 124
Lasse V. Karlsen Avatar answered Oct 21 '22 12:10

Lasse V. Karlsen