Or: “Environmentally Friendly Coding – Recycle Your Keywords”
Yesterday I logged a Quality Central report proposing the addition of support for “automatic variables” to the Delphi language. Not only is it an excellent idea (in my humble and utterly objective opinion
), but there is already a keyword in the language that could be co-opted for this purpose, a keyword that has been at something of a loose-end since it was deprecated (rendered obsolete even) a long, long time ago…
The language keyword in question is automated. This was introduced in Delphi 2.0 as part of the initial implementation to support COM automation and, if memory serves, deprecated in the very next release when “proper” (albeit COM) interfaces were added to the language.
The functionality that AutoFree() provides is similar to the concept of an auto pointer – a specific variant of the general concept of a smart pointer. “auto”… “automatic”… “automated”… the similarity in the terms, and the relevance of the semantics, is striking. To me at least.
The proposal in Quality Central drew inspiration directly from exchanges in the comments on my post on an AutoFree() implementation and a realisation that the required behaviour is very similar to that already implemented for interface references – it would not be entirely alien to the Delphi language.
Indeed I believe it would be quite easily understood and welcomed by most, if not all, developers.
The Proposal
The automated keyword should be supported as a decoration on variable declarations. That is local variables, member variables and unit variables:
interface
type
TFoo = class
private
fBar: TBar automated;
end;
implementation
var
_Bar: TBar automated;
function FooFn;
var
bar: TBar automated;
begin
:
end;
The rules for the keyword and the effect of it shall be as follows:
- The automated keyword shall be valid only for pointer and object reference type variables. (*)
- When marked as automated the compiler shall emit code to initialize a variable to NIL. This already occurs for local variables of certain types, most notably interface references, as well as all member variables (albeit indirectly in that case), and currently has to be specified directly, if required, for unit variables.
- When marked as automated the compiler shall emit code to finalize a variable in a manner appropriate to it’s type. For object references this shall be a call to Free; for pointers a call to FreeMem(). This is directly equivalent to the code already emitted by the compiler to finalize interface references by calling Release().
- automated would not be combinable with absolute.
(*) – it could also be supported on record types with the proviso that the record type in question supports a parameterless constructor (to be called to initialize the record) and a lone destructor (called to finalize the record). But to keep things simple lets stick to object references and pointers, for now at least.
The effect on code of the use of this keyword would be to facilitate:
1. resource protection for temporary objects held in local variables without the need for try..finally blocks.
2. reliable clean up of dependent objects in object hierarchies without the need for objects to implement a destructor (solely) to free those dependent objects. Destructors may still be necessary for other purposes of course.
3. reliable clean up of unit (a.k.a “global”) objects without the need for a unit finalization. Again, finalization may still be required for other purposes.
Note however that it would not prevent these existing techniques from functioning, if required or preferred.
There is only one possible danger that I foresee, which is that a developer might mark a variable as automated but then dispose of the referenced object/memory explicitly without re-initializing the variable. e.g.:
procedure SomeFn;
var
bar: TBar automated;
begin
bar := TBar.Create;
bar.Free;
end;
In this case, when SomeFn exits, the finalization of bar will likely result in an error since bar has been left holding a reference to an object that has already been Free‘d.
Note that the initialization of bar as NIL (as a consequence of being automated) specifically avoids any problem if bar is only assigned a reference conditionally in the code.
Note also that explicitly disposing an automated variable is not in and of itself problematic, as long as the variable is also then explicitly re-set to NIL. In the above example, if bar had been NIL‘d once freed, or FreeAndNIL() had been used, then there would not be any problem with the automated behaviour of bar.
The code below illustrates safe explicit disposal and potentially conditional assignment of an automated reference:
procedure SomeFn;
var
bar: TBar automated;
begin
bar := TBar.Create;
// do some work with "bar"
FreeAndNIL(bar);
if SomeCondition then
begin
bar := TBar.Create;
// do more work with a new "bar"
end;
end;
This code is perfectly safe, will not result in a runtime error and will not leak a TBar.
The potential dangers and pitfalls of an automated variable behaviour implemented as described are actually no different to the potential dangers and pitfalls associated with the manual techniques that it could replace.
I should also mention that I cannot see that the proposal described here would necessarily interfere with, or be interfered with by, the existing, deprecated usage of the automated keyword.
A final observation is that this implementation “feels very Pascal’ly” to me. In a good way.
Call To Action
The Quality Central report # is 67324.
If you feel the idea has merit please vote for it.
If you feel it needs refining, comment on it (in QC, rather than here).
Tags: Delphi, smart pointers
-
Great idea, Jolyon. Voted!
-
+1
Maybe will be a good idea to post it also in to the non-tech CG forum.
-
How do we determine correct vs incorrect use of automated?
How will SomeObj behave in the examples below?Ex.1
var
__SomeObj : TObjType; automated;
begin
__SomeObj := TSomeObj.Create;
// set some props
__SomeContainer.Add(SomeObj);
end;Ex.2
var
__SomeObj : TObjType; automated;
begin
__SomeObj := SomeContainer.Lookup(Key);
// set some props
end; -
Since I’m a fun of the idea, I’ still wondering for more complex cases (object graphs with automated objects inter-dependencies) if the order of automatic “destruction” will have any impact …
For simple cases: automated will be just some sort of syntax sugar that will hide the fact that the compiler will inject the actual Free calls in Finalization (for unit vars), at frame exit (for procedures/functions) and actual owner destructors (for members) …
This will not be a real GC-ed solution, but it will behave (partially) like one !
-
Someone else had this idea ‘a long way in time’ before.
(no, it isn’t mine)See
http://delphi.wikia.com/wiki/Delphi_Suggestions_-_Compiler
(look for Automatic Create/Free down to page – nice discussion there pointing other pitfalls for this)Also, see Ralf Stocker’s QC#32076
A more clearer and safer solution would be, perhaps, in-line var/’using’ which will limit also the scope of the object. (QC #63369)
Just an aside, why don’t you discuss this in a newsgroup? It’s a better environment there (more eyes, threaded layout, easy comment notification, no blog engine quirks (for code posting, angled braces) aso.
Just my2c,
m. Th.
-
What about the next sample?
procedure SomeFn;
var
bar1: TBar automated;
bar2: TBar automated;
c:Tobject;
begin
bar1 := TBar.Create;
bar2: =bar1;//hidden finalization
bar1.Free;
bar2.Free;
end;May be just a form of C# Using keyword?
var
bar1: TBar
bar2: TBar
c:Tobject;
begin
Using bar1 := TBar.Create;
begin
bar2: =bar1;
..
end;
end; -
I am slightly uncomfortable with this construct. It differs in behaviour from strings, dynamic arrays and interfaces which release on scope as well on explicit free (SetLength or set to nil), by the use of reference counting.
If I use an automated object reference, I am having problems seeing how I can work with that variable and pass it into another object graph for keeping, unless there some sort of reference counting so that I don’t accidentally auto-free an object which I have passed on.
-
This is a good idea.
Self aborption warning: I also suggested an AUTO directive:
http://nafdb.blogspot.com/2007/04/first-screenshots-of-delphi-2010-for.html
-
Hi.
What about
whith a := TSomething.Create() do
begin…
endor to avoide type inference:
with a: TSomething = TSomethig.Create() do…
And all this with autofreeing when out of scope.
-
Hi,
I think a better syntax might be:
instead of:
—
var
__SomeObj : TObjType; automated;
—
rather use:
—
automated var
__SomeObj : TObjType;
another_obj: TMyObject; //also automated
var
RegVar : TMyOtherObject; //non-automated
…
—we already have a threadvar, so this is another var block type…
-
One other thing one must be careful of is, that by looking at the variable one can’t easily determine how it is destroyed/freed (automatic or not) which can easily lead to programming errors or forgetting to free normal objects that the programmer might have assumed is auto freed, etc.
The language must not make the programmer guess how a variable works or does, the code / variable must be able to say as much about itself as possible on it’s own (for example interfaces have an ‘I’ prefix (albeit optional, Types a ‘T’, etc.) but all this makes the code readable by others way after it’s written and that’s what the spirit of Pascal / Delphi is all about.
One idea might be and IDE feature that can super-impose a tiny glyph (like a tiny “A”) wherever a variable is used to indicate it’s type & certain features, but must be always visible, so just reading or scanning the code immediately gives one an indication of the functionality of a variable.
An integer would have a tiny “int” glyph in the bottom corner of every integer, a tiny “str” glyph for strings, etc. Totally removing need for hungarian notation and the like (readable variables are still important though

Maybe this can be something tools like Castalia could tackle.Another useless 0.02cents
-
I don’t like the idea at all. The feature proposed just makes your code more prone to errors.
-
And intermediate solution would be an optional finally keyword in blocks and variable assignments for definition:
procedure foo;
var
list : TList := nil
begin
[...]
finally
list.free;
end;or even better:
procedure foo;
var
list : TList := TList.Create;
begin
[...]
finally
list.free
end; -
Here is another variant:
procedure foo;
var
list : TList := TList.Create & finally free;
begin
[...]
end; -
And an other one:
I finish with this one…procedure foo;
var
list : TList.Create & finally free;
begin
[...]
end; -
besides that, there are other reasons for manual allocation besides speed, namely predictability, and a guarantee that resources won’t be kept longer than specified (at least from the viewpoint of the program, the heapmanager is something altogether different).
IMHO proposals like this are a hack. If you want automatic resources that bad, use a language designed for it.
Comments are now closed.


DelphiFeeds
29 comments