4
votes

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.
2
Why are you implementing constructors on legacy Turbo Pascal objects? That should be a procedure, and it should be called Initialize.David Heffernan
@LaKraven There is no inherited Create. This is object and not class.David Heffernan
Didn't spot that, @DavidHeffernan. Cheers!LaKraven
This is not originally my code, just something that has fallen into my hands, so I can't say the original motivations of the author. As far as I know the intent of the Create and CreatePos methods is just to initialize the structure, so I'd guess that calling them constructor is just an idea to make them visually stand out from the code as initialization methods. But since I'm not sure, that's basically what I'm asking here, i.e. is there any functional difference between 'constructor' and 'procedure' here, why I should not just change the term? Also, curiosity, why XE3 gives error and XE2not?DelphiUser

2 Answers

7
votes

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!

6
votes

I have a simple piece of code, that compiles in Delphi XE2 but not in XE3, and I don't know why.

You are trying to call a constructor inside of a method of an instance that is already instantiated and initialiized. The compiler does not allow that anymore. More specifically, this code:

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

Is the same as this code:

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

And you cannot call a constructor on the Self variable anymore. Why? IIRC, it has to do with compiler's ongoing shift to supporting mobile development.