Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Delphi XE3 gives "E2382 Cannot call constructors using instance variables"?

I have a simple piece of code, that compiles in Delphi XE2 but not in XE3, and I don't know why. I have reduced the problematic code to a small bit and would like to know what's wrong with it in Delphi's opinion. Trying to compile a project containing this unit in Delphi XE 2 works fine, but in Delphi XE3 (trial), it gives "[dcc32 Error] AffineTransform.pas(26): E2382 Cannot call constructors using instance variables". The only "eccentric" thing I know of here is the use of the old-school "object" type, where the constructor isn't really exactly the same thing as in real objects (TObject-based class instances).

If I replace the words 'constructor' in this object with 'procedure', then it compiles ok, but why is this, and is this an ok change to do in my code, i.e. is it a change that will have no effect on the functionality?

unit AffineTransform;

interface

type
  { Rectangular area. }
  TCoordRect = object
  public
    Left, Top, Right, Bottom: Real;
    constructor CreatePos(ALeft, ATop, ARight, ABottom: Real);
    procedure   Include(AX, AY: Real);
  end;

implementation

constructor TCoordRect.CreatePos(ALeft, ATop, ARight, ABottom: Real);
begin
  Left := ALeft;
  Top := ATop;
  Right := ARight;
  Bottom := ABottom;
end;

procedure TCoordRect.Include(AX, AY: Real);
begin
  CreatePos(AX, AY, AX, AY)
end;

end.
like image 315
DelphiUser Avatar asked Dec 12 '22 21:12

DelphiUser


1 Answers

For this legacy Turbo Pascal style object, there is really no meaning to the keyword constructor. Although an object constructor does have some special treatment, there's absolutely no need for that here. What have here is nothing more than a record with some methods.

The XE3 compiler was changed so that it no longer allows you to call a constructor on Self inside an instance method. That is the case for both class and object. I've not seen any documentation of why this change was made. No doubt in time it will seep out.

Your immediate solution is to replace constructor with procedure. In the longer term, it would make sense to turn this into a record rather than an object.


I would also council you to change the name of the method to Initialize. Some library designers seem to opt for using Create and Free methods on their records. This had led to immense amount of code being written like this:

ctx := TRttiContext.Create;
try
  ....
finally
  ctx.Free;
end;

In fact all that code is spurious and can simply be removed! A TRttiContext variable will automatically initialize itself.

That sort of design also sets a giant Heffalump Trap for that faction of Delphi coders that like to use FreeAndNil. Passing a record to FreeAndNil leads to some interesting fireworks!

like image 189
David Heffernan Avatar answered Dec 22 '22 01:12

David Heffernan