Kennisbank

Stop het gebruiken van WITH in Delphi

Wat doet WITH?

Het with-statement maakt al deel uit van Object Pascal sinds de begindagen van Pascal. Het was ontworpen om typen te besparen door je toe te staan de objectnaam weg te laten bij het benaderen van properties en methoden. In de praktijk introduceert with subtiele bugs en maakt het code moeilijker te lezen en te onderhouden. Bij GDK Software raden we het gebruik ervan sterk af.

Het with -statement brengt de leden van een object of record tijdelijk in scope, zodat je ernaar kunt verwijzen zonder een qualifier:

with MyButton do
begin
  Caption := 'Click me';
  Enabled := True;
  Width   := 120;
end;

Op het eerste gezicht ziet dit er overzichtelijk uit. De problemen beginnen wanneer je codebase groeit.

Waarom je ermee moet stoppen

1. Stille scope wijzigingen

Het grootste gevaar van with is dat je code stilletjes van betekenis kan veranderen wanneer iemand een nieuwe property toevoegt aan een klasse, inclusief klassen in de RTL of een externe bibliotheek. Overweeg het volgende:

with MyRect do
begin
  Left  := 10;
  Top   := 10;
  Width := GetWidth;  // Which Width? MyRect.Width or the enclosing form's Width?
end;

Als een toekomstige versie van Delphi een Width-property toevoegt aan TRect (wat inderdaad is gebeurd), lost de compiler Width stilzwijgend op naar TRect.Width in plaats van de buitenste scope. Geen waarschuwing, geen fout, alleen onverwacht gedrag tijdens runtime.

2. Debugger ondersteuning werkt niet goed

De Delphi-debugger kan variabelen binnen een with-blok niet betrouwbaar evalueren. Wanneer je over een identifier zweeft om de waarde te inspecteren, weet de debugger niet in welke scope hij moet zoeken. Dit maakt debuggen aanzienlijk moeilijker en kost je kostbare tijd.

3. Leesbaarheid lijdt eronder

Code wordt veel vaker gelezen dan geschreven. Wanneer een collega (of jijzelf in de toekomst) een with-blok leest, moeten ze mentaal bijhouden bij welk object elke identifier hoort. Met geneste with-statements wordt dit vrijwel onmogelijk:

with Order, Customer, Address do
begin
  City := 'Amsterdam';  // Which object owns City?
end;

4. Het is een tijdbom voor onderhoud

Naarmate je applicatie evolueert, kunnen nieuwe properties worden toegevoegd aan elk van de betrokken types. Elke dergelijke wijziging is een potentiële stille bug binnen een with-blok. De compiler waarschuwt je niet, en het probleem komt mogelijk pas aan het licht wanneer een klant onverwacht gedrag meldt.

Wat je in plaats daarvan kunt doen

Gebruik een lokale variabele om referenties beknopt te houden zonder de scope te verbergen:

var Btn := MyButton;
Btn.Caption := 'Click me';
Btn.Enabled := True;
Btn.Width   := 120;

De code is even beknopt, elke identifier is ondubbelzinnig, en de debugger werkt perfect.

Gebruik voor records een lokale pointer of inline variabele (beschikbaar sinds Delphi 10.3):

var Rectangle: TRect := GetBounds;
Rectangle.Left := 10;
Rectangle.Top  := 10;

Conclusie

De with-statement bespaart een paar toetsaanslagen, maar introduceert verborgen risico’s: stille scopewijzigingen, gebrekkige debuggerondersteuning en moeilijk leesbare code. Bij GDK Software gebruiken we with nooit in productiecode. Vervang het door een duidelijk benoemde lokale variabele, en je toekomstige zelf en je collega’s zullen je dankbaar zijn.

Voor meer Delphi best practices, lees ons artikel over Delphi Tips & Tricks.

Geschreven door Alan Bariani
Delphi ontwikkelaar

Contact

Laat ons helpen jouw ambities concreet te maken.