Is Delphi "with" keyword a bad practice?

Solution 1:

The biggest danger of with, outside of pathological conditions like "with A, B, C, D" is that your code can silently change meaning with no notice to you. Consider this example:

with TFoo.Create
try
  Bar := Baz;
  DoSomething();
finally
  Free;
end;

You write this code knowing that Bar is a property of TFoo, and Baz is a property of the type containing the method which has this code.

Now, two years later, some well-meaning developer comes in adds a Baz property to TFoo. Your code has silently changed meaning. The compiler won't complain, but the code is now broken.

Solution 2:

The with keyword is a nice feature for making your code more readable but there are some pitfalls.

Debugging:

When using code like this:

with TMyClass.Create do
try
  Add('foo');
finally
  Free;
end;

There is no way to inspect the properties of this class, so always declare a variable and use the with keyword on that.

Interfaces:

When creating an interface in the with clause it lives till the end of your method:

procedure MemoryHog;
begin
  with GetInterfaceThatTakes50MBOfMemory do
    Whatever;
  ShowMessage('I''m still using 50MB of memory!');
end;

Clarity

When using a class in a with clause that has properties or method names that already exists within the scope, it can fool you easily.

with TMyForm.Create do
  Width := Width + 2; //which width in this with is width?

Of course when having duplicate names, you're using the properties and methods of the class declared in your with statement (TMyForm).

Solution 3:

The with statement has its place but I have to agree that overuse can lead to ambiguous code. A good rule of thumb is to make sure the code is "more" readable and maintainable after adding the with statement. If you feel you need to add comments to explain the code after adding the statement then it is probably a bad idea. If the code is more readable as in your example then use it.

btw: this was always one of my favorite patterns in Delphi for showing a modal window

with TForm.Create(nil) do
try
  ShowModal;
finally
  Free;
end

Solution 4:

I tend towards baning the with-statement altogether. As previously stated, it can make things complicated, and my experience is that it will. Many times the debugger want evaluate values because of withs, and all to often I find nested withs that lead to code that hard to read.

Brian's code seems readable and nice, but the code would be shorter if you just typecast the sender directly, and you remove all doubt about that component you enable:

TAction(Sender).Enabled := Something;

If you are concerned about typing to much, I prefare to make a temporary referance to the long-named object:

var
  t: TTable;
begin
  t := theLongNamedDataModule.WithItsLongNamedTable;
  t.FieldByName(' ');
end;

I can't se why typing should bother you, though. We Are Typists First, Programmers Second, and code-completion, copy-paste and key-recording can help you be a more effective typist.

update: Just stumbled over an long article with a little section on with-statements: he with keyword. The most hideous, dangerous, blow-your-own-feet-off feature in the language. :-)