Why is this an issue?

The with statement in Delphi, though seemingly clean and convenient, can introduce a host of issues that hinder code clarity and maintainability.

It can lead to ambiguity and confusion. Identifiers within a with block may refer to local variables, members of the Self object, or members of the objects targeted by the with statement. This lack of clarity makes it harder to discern the origin and purpose of variables.

Additionally, with statements can potentially obscure variables declared in an outer scope, creating scope ambiguity and increasing the likelihood of unintended consequences.

Worse still, the use of with can lead to surprising bugs, especially when an object within the with statement shares a member name with the Self object. Removing a class member can cause an overloaded with to select the other name, masking what would have been a compilation error if the field were accessed more explicitly.

How to fix it

Remove the with statement and qualify any accesses within it:

procedure TMyForm.MyEvent(Sender: TObject);
begin
  with TButton.Create(Self) do begin
    Parent := Self;
    Left := 50;
    Top := 20;
    Caption := ClassName;
    Color := clRed;
  end;
end;
procedure TMyForm.MyEvent(Sender: TObject);
var
  MyButton: TButton;
begin
  MyButton := TButton.Create(Self);
  MyButton.Parent := Self;
  MyButton.Left := 50;
  MyButton.Top := 20;
  MyButton.Caption := ClassName;
  Self.Color := clRed;
end;

Resources