Thanks for the clarification,
@440bx - the single-arg restriction sidesteps the multi-arg objection. And on your point 2 - actually that already works for
defer today. Defers fire at the matching
end of whatever block they're declared in, not at the end of the routine. Quick demo:
program app;
{$mode unleashed}
procedure main;
begin
writeln('begin');
defer writeln('end');
begin
defer writeln('end of block');
writeln('inside block');
end;
if true then begin
defer writeln('exiting if');
writeln('im in the if');
end;
writeln('bye');
end;
begin
main;
readln;
end.
Output:
begin
inside block
end of block
im in the if
exiting if
bye
end
So scope-of-declaration would carry over to declaration-attached defer for free.
The one thing I'm still stuck on is
sentinel detection. The boolean defer-flag tracks "was the line reached", not "was the variable assigned" - and with declaration-attached defer, the flag fires on declaration, before init. To make it safe you'd need a sentinel value at declaration (
= INVALID_HANDLE_VALUE,
= nil, etc.) plus a runtime check before cleanup. Works for pointers and Windows handles, but plenty of types have no natural sentinel - booleans, integers where 0 is valid, plain records, custom enums.
And realistically - if you want RAII-style scoped cleanup for arbitrary resources, that's already covered by
autofree (for class instances) and managed records (for value types with
class operator Finalize). Wrap the
THANDLE in a small class:
type
TScopedHandle = class
handle: THANDLE;
constructor Create(h: THANDLE=INVALID_HANDLE_VALUE);
destructor Destroy; override;
end;
constructor TScopedHandle.Create(h: THANDLE);
begin
handle := h;
end;
destructor TScopedHandle.Destroy;
begin
if handle <> INVALID_HANDLE_VALUE then CloseHandle(handle);
end;
Then in your code:
var token := autofree TScopedHandle.Create;
// scope exit -> Free -> CloseHandle if valid
The cleanup is owned by the type, user just declares an instance, no separate
defer needed. That's the RAII pattern, working today. The
defer-on-variable proposal would be a third mechanism on top of two that already cover the same ground - which is part of why I'm hesitant.
Plus the reader-model thing -
CloseHandle firing while the variable wasn't assigned (or was reset to sentinel) looks weird unless you know the mechanism.