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.
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.
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.
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;
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.
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;
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.
Contact