Delphi – bizarre use of class helpers to circumvent ‘with’
Posted by jpluimers on 2009/04/27
Quite a while ago, a co-worker asked how to get tot the Instance variable when using a with statement like this:
function TMyForm.ExecuteForm(FormClass: TFormClass): Integer; begin with FormClass.Create(self) do try Result := ShowModal; finally Free; end; end;
So I wrote the blog entry below when I started my blog last week, and set the published date to somewhere early May, a week that will be really busy.
Then I found out about the Stackoverflow question Reference object instance created using “with” in Delphi followed by the answer by user ‘Alexander‘ (a really smart Russian guy).
Enough coincidence to publish the blog article earlier than scheduled :-)
Before I explain why I really hate ‘with’, lets show what my co-worker wanted, and my solution:
uses ObjectHelperUnit; // ... function TMyForm.ExecuteForm(FormClass: TFormClass): Integer; begin with FormClass.Create(self) do try // just an example on how you could use Instance: TForm(Instance).Caption := Instance.ClassName; Result := ShowModal; finally Free; end; end;
First, let me show a few examples why ‘with’ is bad:
- the debugger cannot peek through with, so you will see different results in the debugger than the code that actually executes. See the question on Debugging problems with ‘WITH’ statement in Delphi 2006 at Stackoverflow or this code:
procedure TMyForm.ButtonClick(Sender: TObject); begin with MyLabel do begin // note: debugger sees the Caption of the Form, but user the Caption of MyLabel! ShowMessage(Caption); end; end;
- it bites you when doing code like this:
procedure TMyForm.ButtonClick(Sender: TObject); begin with MyEdit do begin // note: MyEdit does not have a Caption! Caption := Sender.ClassName; end; end;
So better not use the class helper, but a local variable:
function TMyForm.ExecuteForm(FormClass: TFormClass): Integer; var ModalForm: TFormClass; begin ModalForm := FormClass.Create(Self); try ModalForm.Caption := ModalForm.ClassName; Result := ModalForm.ShowModal; finally ModalForm.Free; end; end;
Back to getting the instance, this too can be solved with class helpers (a special compiler feature that was introduced quite a few Delphi versions ago for .NET portability reasons and since Delphi 2005 has been backported to the Win32 version of the compiler).
The nifty class helper below will get you going doing your bizarre “with circumvention”.
Edit @ 20090429: Stackoverflow user Vegar correctly noted that this will effectively kill any other class helpers for TObject or its descendants. Yet another reason not to use with :-)
So, before you read further, read this disclaimer:
“Try to avoid with. With stunts are performed by professionals. Please do not try them at home, work or any other place.”
–jeroen
unit ObjectHelperUnit; interface type TObjectHelper = class helper for TObject public function Instance: TObject; // trick to circumvent the 'with' statement end; implementation { TObjectHelper } function TObjectHelper.Instance: TObject; begin Result := Self; end; end.
Delphi: you should avoid the `with` statement as it makes your code less future proof « The Wiert Corner – irregular stream of stuff said
[…] I wrote before, I’m with the Delphi with haters camp, and this is […]
Delphi – record and class helpers: an overview of useful linksoo « The Wiert Corner – Jeroen Pluimers’ irregular stream of Wiert stuff said
[…] The Wiert Corner: class helper to circumvent ‘with’ […]