Delphi 10.1 Berlin adds a couple of features to the Delphi language, bridging gaps between platforms and extending the Win32/Win64 interface reference model. This is not the only change to the language, but clearly the most relevant one. Another, focused on mobile, is the introduction of the native UTF8String type on all platforms, mobile compilers included.

But let me get back to the way references to interfaces work on the desktop compilers. By default, all references to interfaces use reference counting. As you assign a variable to the interface the reference count is increased, as the variable is set to nil or goes out of scope, the reference count is decreased. When the reference count gets to zero the object is deleted from memory. That is not actually always true, as the actual behavior is implemented by each class, so you can write a class that implements an interface and ignores the reference counting mechanism.

Anyway, getting back to the common scenarios in which reference count is active, you can have code like the following, which relies on reference counting to dispose the temporary object:

procedure TForm3.Button2Click(Sender: TObject);
var
  one: ISimpleInterface;
begin
  one := TObjectOne.Create;
  one.DoSomething;
end;

What if the object has a standard reference count implementation and you want to create an interface reference that is kept out of the total count of references? You can now achieve this by adding the [unsafe] attribute to the interface variable declaration, changing the code above to:

procedure TForm3.Button2Click(Sender: TObject);
var
  [unsafe]
  one: ISimpleInterface;
begin
  one := TObjectOne.Create;
  one.DoSomething;
end;

Not that this is a good idea, as the code above would cause a memory leak. By disabling the reference counting, when the variable goes out of scope nothing happens. There are some scenarios in which this is beneficial, as you can still use interfaces and not trigger the extra reference. In other words, an unsafe reference is treated just like... a pointer, with no extra compiler support.

Now before you consider using the unsafe attribute for having a reference without increasing the count, consider that in most cases there is another better option, that is the use of weak references. Weak references also avoid increasing the reference count, but they are managed. This means that the system keeps track of weak references, and in case the actual object gets deleted, it will set the weak reference to nil. With an unsafe reference, instead, you have no way to know the status of the target object (a scenario called dangling reference).

In which scenarios are weak reference useful? A classic case is that of two object with cross-references. In such a case, in fact, the object would artificially inflate the reference count of the other objects, and they'll basically remain in memory forever (with reference count set to 1), even when they become unreachable.

As an example consider the following interface, accepting a reference to another interface of the same type, and a class implementing it with an internal reference:

type
  ISimpleInterface = interface
    procedure DoSomething;
    procedure AddObjectRef (simple: ISimpleInterface);
  end;

  TObjectOne = class (TInterfacedObject, ISimpleInterface)
  private
    anotherObj: ISimpleInterface;
  public
    procedure DoSomething;
    procedure AddObjectRef (simple: ISimpleInterface);
  end;

If you create two objects and cross-reference them, you end up with a memory leak:

var
  one, two: ISimpleInterface;
begin
  one := TObjectOne.Create;
  two := TObjectOne.Create;
  one.AddObjectRef (two);
  two.AddObjectRef (one);

Now the solution available in Delphi 10.1 Berlin is to mark the private field anotherObj as weak:

private
  [weak]
  anotherObj: ISimpleInterface;

Now the reference count is not modified when you pass the object as parameter to the AddObjectRef call, it stays at 1, and it goes back to zero when the variables go out of scope, freeing the objects from memory.

Now there are many other cases in which this feature becomes handy, and there is some real complexity in the underlying implementation. It is great feature, but one that takes some effort to fully master. Also, it does have some runtime cost, as weak references are managed (while unsafe ones are not).