Category Archives: Best Practices

Interface better practices

Today’s post is inspired from a question I answered on stackoverflow a while ago.  I’m bringing you some important point to consider when using interface.

First, one thing worth mentioning is that interface are not necessarily reference counted.  For example, TComponent implements IInterface, but if we look at it’s AddRef and Release methods, they both returns -1 indicating no reference counting occurs. TInterfacedObject, on the other hand, does take care of the reference counting. This is an important distinction because it affects how we should use interface.

Reference-counted interface

When using those, it’s usually preferable to avoid keeping a reference to the implementing object as we have no control on the lifetime of the object, the object will get destroyed at the same time it’s last interface reference is cleared.

If we absolutely need to keep the object reference around, we have 2 options.

  1. Keep an interface variable alongside the object variable to keep the object alive.
    TMyClass = class(TInterfaceObject);
    [...]
    TForm1 = class(TForm)
      FObject : TMyClass;
      FObjectIntf : IUnknown; 
    public
    [...]
    //Creating the object
    FObject := TMyClass.Create;
    FObjectIntf := FObject;
    //Destroying the object
    FObject := nil; //Do NOT free the object
    FObjectIntf := nil; //FObject's Destructor is called here.
    
  2. Use a FreeNotification mechanism to set the object’s variable back to nil when it is freed. This is built-in TComponent. Even though our class isn’t derived from TComponent, we can still leverage the functionality like this :
    TMyClass = class(TInterfaceObject)
      FNotifier : TComponent
    [...]
    TForm1 = class(TForm)
    private
      FObject : TMyClass;
    protected 
      procedure Notification(AComponent: TComponent; Operation: TOperation);override;
    
    
    [...]
    procedure TForm1.Notification(AComponent: TComponent; Operation: TOperation);
    begin
     inherited;
     if FObject.FNotifier = FComponent then
       FObject := nil;
    end;
    //Creating the object
    FObject := TMyClass.Create;
    Form1.FreeNotification(FObject.FNotifier);
    //Destroying the object
    FObject.Free;  //Here, FObject is assigned.
    Assert(FObject = nil); //Here, FObject is not assigned anymore, it was set to "nil" in TForm1.Notification.
    

When working with reference counted interface, it is worth nothing that, if 2 interfaces reference each others, they are never going to be freed. This is called “Circular Reference”. This is also seen with Automatic Reference Counting (ARC). The best method to break circular reference is a subject I still have to research (Especially in regard to the new [weak]  keyword) so I won’t make any suggestion here, but I thought it was worth mentioning.

Non reference-counted interface

Here, we need to keep an object reference around to be able to free our object’s memory as it won’t be freed through reference counting and, unless it implements IDisposable or a similar interface, we can’t free it from the interface reference.  Thus, we have the opposite problem.  We are unable to determine if there are references to our object left.

That being said, the problem isn’t specific to interface. The same problem would occur if we would pass the reference to our object around as a simple object.  Since this post is more about interfaces, I won’t delve into it here (though I might write about it some other time). But, one of the ways to make sure no references are left to our object is (*drum roll*), FreeNotification.

In which circumstance would we want to use interface without the reference counting?  Interfaces are tools and a tool’s usefulness is mostly limited by one’s imagination. But one I can name on the top of my head is using it as a “method binding” technique or pseudo “Duck Typing“. One such example can be seen in one of my previous post here.  Interface is also pretty much how anonymous methods are implemented “behind the scene”. I’m sure you guys can figure out clever usage for them!

Allowing breaking changes to break is good

I remember a discussion with a coworker some time ago… He came and proudly told me he always used “.AsString”, “.AsInteger”, etc when dealing with TField’s descendant instead of using “.Value”. His rational was that, if the field type changes, using Value would would not compile while using AsString would.

Take the following code :

  
  FField.AsString := 'Hello World';
  FField.Value    := 'Hello World';

If FField is a TWideString field, both line means essentially the same. On the other hand, If FField is a TIntegerField, the 2nd line won’t compile.

While I need to admit my coworker was right, his approach was certainly better than mine at making sure a given line of code will keep compiling in the future, he was also wrong in believing this was a good thing.

In this particular example, even though FField.AsString would keep compiling if FField become a TIntegerField, it would just raise an exception at runtime trying to convert ‘Hello World’ to an Integer.

Personally, I tend to favor coding approach that will allow the compiler to catch problems at compile time. It’s one of the perks of working with a strongly typed language.

So, what do *I* do? I always use Field.Value for typed TField. When I’m working with untyped TField variable, then I never use Field.Value.

  
  var
    FTypedField   : TWideStringField;
    FUntypedField : TField;
    sSomeVariable : String;
[...]
  FTypedField.Value       := sSomeVariable ; 
  FUntypedField.AsString  := sSomeVariable ;

In this situation, if FTypedField becomes a TIntegerField, the code won’t compile. But why use AsString with an TField?  In this case, the advantage lies on the right side of the operation : If sSomeVariable’s type is changed, that won’t compile anymore.