AUTOREFCOUNT and the Free Pattern

The more I use the Delphi mobile compiler and its automatic reference counting (ARC), the more I am coming to the conclusion that Embarcadero chose the wrong implementation pattern for the Free code.  Now I am not getting into the pros and cons of ARC here, I am just referring to how the Free method in the ARC compiler is mapped to nil in mobile code.  It should have stayed a Free/DisposeOf method instead.

Why do I think it was mistake?

1.  If Free is used in ARC code, the developer is porting code from other compilers.  He/she wants this behavior.  If the developer is writing from scratch for mobile (and only mobile), he will omit the Free call (or use DisposeOf).  Even worse, for the component developer, the DisposeOf option is not available.  We have to leave the Free call in as the code must work in earlier versions of Delphi.

2. The ARC compiler’s unfortunate decision to output a hint when it encounters a Free call means I usually end up mapping the Free to DisposeOf with very ugly IFDEFs anyway to get rid of the hint, e.g.,

aObject.{$IFDEF AUTOREFCOUNT}DisposeOf;{$ELSE}Free;{$ENDIF}

3. Mapping Free to nil makes destruction of objects non-deterministic from the developer’s point of view.  From the point of view of the program, of course, it is completely deterministic: destruction occurs when there are no more references to the object.  However, from the developer’s point of view, mapping Free to reference = nil is not deterministic, as the call to Free may not do anything!  It is especially bad as the behavior from non-ARC to ARC changes.  Often, I depend on the destruction of an object to notify other objects.  If that destruction doesn’t happen or happens at a different time, bad things can happen.

Objections

Now, there are plenty of objections you can make to this.

ARC is supposed to make our code more robust, and the Free method bypasses that safety.  However, Embarcadero supplies the DisposeOf method to get around that safety anyway!  Why couldn’t the Free call have stayed the method for forcing destruction?

Disposing of the object when there are still references can cause access violations!  Well, maybe… and maybe not.  The TComponent memory management architecture (using notification) means that there can be multiple references to a component, but that the destruction of a component can clean them all up.  And I would argue that I *want* to see these problems otherwise.  I am porting from a non-memory managed compiler.  If I haven’t cleaned this up properly on non-ARC, it is a bug.  It should be a bug here.

What happens in practice, except for simple classes, is that the Destroy code gets called at an unexpected moment and then causes access violations or other unexpected behavior that the developer did not expect.  It is very difficult to debug this late destruction behavior.

So to close, the Free method should have stayed Free! (I feel very patriotic for some reason right now 🙂 )  Not only would it have made the look of the code much better (without ugly IFDEFs), the behavior of the code between compilers would have stayed more alike and easier to debug.