Is the implementation of Delphi interface reference counting future proof - delphi

I have a helper class that will be in wide use across the application. The implementation relies on interface reference counting, the idea roughly is:
...
var
lHelper: IMyHelper;
begin
lHelper := TMyHelper.Create(some params);
...some code that doesn't have to access lHelper
end;
So the implementation relies on IMyHelper going out of scope at the end of the method, but not before.
So what am asking is, can I be certain that in some future Delphi compiler won't play smart and release the interface right after it's created if the variable is not accessed in rest of the method ?

IMHO you can be confident of that. The out-of-scope pattern will probably remain global to the instruction block of this method. This would be a breaking change.
See this comment from Barry Kelly (from Embarcadero):
As to your earlier comment, about explicit variables: in the hypothetical (and breaking change) case, where we optimized interface variable usage, we would likely not only break the described RAII-like functionality but also the explicit variable approach too; the values assigned to FooNotifier and BarNotifier are not used, so "in theory" they can be freed up sooner, and potentially even reuse the same storage.
But of course, destruction of the interface can have side-effects, and that's what's being relied upon for the effect in the post. Changing the language such that side-effects like these have visible changes is not something we do willingly.
So you can guess that Embarcadero won't introduce any backward compatibility change here. The benefit of re-using an interface memory won't be worth breaking compatibility and introducing side effects: saving a pointer (4 or 8 bytes) is not worth it nowadays, especially when the stack is already allocated, and aligned (x64 model uses more stack than x86).
Only if a Garbage Collector is introduced to the language (which I do not want from my personal point of view), objects life time may change. But in this case, life time may probably be longer.
In all cases, you can create your own code, to be sure that it will released at the end of the method:
var
lHelper: IMyHelper;
begin
lHelper := TMyHelper.Create(some params);
try
...some code that doesn't have to access lHelper
finally
lHelper := nil; // release the interface count by yourself
end;
end;
In fact, this is the code already generated by the compiler. Writing this will be perfectly redundant, but it will ensure that compiler won't cheat on you.
When speaking of interfaces and reference counting, please take in account the potential issue of circular references in Delphi. See this great article (i.e. "Example 2-15") about the need of "weak pointers" for circular references of Interfaces.
Other languages (like Java or C#) use a garbage collector to resolve this. Objective C uses an explicit "zeroing weak pointers" mechanism to solve it - see this discussion or this SO answer for a potential implementation. Perhaps future version of Delphi may consider using an implementation similar to the ARC model introduced in Objective C. But I suspect there will be an explicit syntax to preserve compatibility with existing code.

The documentation says this (emphasis mine):
On the Win32 platform, interface references are typically managed through reference-counting, which depends on the _AddRef and _Release methods inherited from System/IInterface. Using the default implementation of reference counting, when an object is referenced only through interfaces, there is no need to destroy it manually; the object is automatically destroyed when the last reference to it goes out of scope.
The scope of a local variable is the method and so the current specification is that _Release will not be called until the method is complete.
There's never a promise that specifications will not be changed in the future but I think the likelihood of a change being made to this part of the language is vanishingly small.

Related

What happens when I free memory that may not exist in Delphi?

Delphi doesn't have a garbage collector, so coming from a Java background this is a real pain in the neck.
Usually, to destroy some memory I won't use anymore I'd use:
if (SomeMemory <> nil) then
SomeMemory.Free
What would happen if I don't check for nil before deleting?
Additionally, why someone would want to deal with all this "garbage collecting" by himself? Why among all the compiling options Delphi has, there is no Garbage Collector = true
The code for TObject.Free looks like this :
procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;
So there is no need to check for nil. You can still get into trouble if you try to free an uninitialized variable, however, as this will result in an AV. Checking for nil (or Assigned) obviously doesn't help you there either. The compiler will warn you if you try to do this, however.
To answer your second question
Why among all the compiling options Delphi has, there is no Garbage Collector = true
The simple answer is that Delphi does not have such a garbage collector. Certain managed types (like strings, dynamic arrays, etc) implement compiler-managed automatic reference counting, and those objects are automatically freed when their reference counts fall to zero. For all other unmanaged objects it is the responsibility of the developer to appropriately clean up object instances when they are no longer needed.
It's not a question of wanting to have to manage your application's memory, it's just a matter of course that you need to.
Checking for nil before Free is redundant. If the reference is nil, then it's already safe to call Free on it. If the reference isn't nil, then the safety of calling Free on it is unchanged and depends entirely on whether the variable contains a valid reference.
For example:
SomeMemory := nil;
SomeMemory.Free; // This is safe.
SomeMemory := TObject.Create;
SomeMemory.Free; // This is safe
Assert(SomeMemory <> nil);
SomeMemory.Free; // This is an error (EInvalidOperation)
In the first block, we don't check whether the variable is null, and yet the call to Free is perfectly safe. It does nothing. In the second block, we see that the variable remains non-null, but calling Free on it yields an exception.
There is a pretty straight-forward way in Delphi to have (something like) garbage collection: use interface pointers. By using variables of a type ultimately derived from IInterface (or IUnknown which is basically the same thing), Delphi will keep close count of the references, and free/destroy/release the instance when the last reference is removed. Using interface pointers, apart from instance creation and a few other things, is almost identical to using object references.
In Nick Hodges' recent work Coding In Delphi, there's quite a bit on this programming technique, and its relations to abstraction, generics, unit testing and dependency injection.
Also new versions of Delphi for other platforms will have ARC (automatic reference counting) on object references as well, operating like interfaces do now. (Obsoleting the Free method, but that's another story.)
You can always consult the documentation in order to answer such a question. Here it is, with my emphasis:
Use Free to destroy an object. Free automatically calls the destructor if the object reference is not nil. Any object instantiated at run time that does not have an owner should be destroyed by a call to Free, so that it can be properly disposed of and its memory released. Unlike Destroy, Free is successful even if the object is nil; if the object was never initialized, Free would not result in an error.
Find a more complete discussion of the issue here: Why should I not use "if Assigned()" before using or freeing things?

How to effectively use interfaces for memory management in Delphi

I'm fairly new to Delphi and have been doing all my memory management manually, but have heard references to Delphi being able to use interfaces to do reference counting and providing some memory management that way. I want to get started with that, but have a few questions.
Just generally, how do I use it. Create the interface and the class implementing it. Then anytime I need that object, have the variable actually be of the Interface type, but instantiate the object and presto? No nee to think about freeing it? No more try-finallys?
It seems very cumbersome to create a bunch of interfaces for classes that really don't need them. Any tips on auto generating those? How do I best organize that? Interface and class in the same file?
What are common pitfalls that might cause me grief? Ex: Does casting the interfaced object to the an object of its class break my reference counting? Or are there any non-obvious ways Delphi would create reference loops? (meaning besides A uses B uses C uses A)
If there are tutorials that cover any of this, that would be great, but I didn't come up with anything in my searches. Thanks.
I am currently working with a very large project that takes advantage of the "side affect" of interface reference counting for the purpose of memory management.
My own personal conclusion is that you end up with a lot of code that is overly complex for no better reason than, "I don't have to worry about calling free"
I would strongly advise against this course of action for some very basic reasons:
1) You are using a side affect that exists for the purpose of COM compatibility.
2) You are making your object footprint and efficiency heavier. Interfaces are pointers to lists of pointers.. or something along those lines.
3) Like you stated... you now have to make piles of interfaces for the sole purpose of avoiding freeing memory yourself... this causes more trouble than it's worth in my opinion.
4) Most common bug that will be a HUGE pain to debug will become when an object gets freed, before it's reference. We have special code in our own reference counting to try and test for this problem before software goes out the door.
Now to answer your questions.
1) Given TFoo and interface IFoo you can have a method like the following
function GetFoo: IFoo;
begin
Result := (TFoo.Create as IFoo);
end;
...and presto, you don't need the finally to free it.
2) Yes like I said, you think it's a great idea, but it turns into a huge pain in the bupkis
3) 2 problems.
A) you have Object1.Interface2 and Object2.Interface1... these objects will never be freed due to the circular reference
B) Freeing the object before all the references are released, I cannot stress how dificult these bugs are to track down...
The most common complaint leading to the desire for "automatic garbage collection" in Delphi is the way that even short-lived temporary objects have to be disposed of manually and that you have to write a fair amount of "boiler-plate" code to ensure that this takes place when exceptions occur.
For example, creating a TStringList for some temporary sorting or other algorithmic purpose within a procedure:
procedure SomeStringsOperation(const aStrings: TStrings);
var
list: TStringList;
begin
list := TStringList.Create;
try
:
// do some work with "list"
:
finally
list.Free;
end;
end;
As you mentioned, objects that implement the COM protocol of reference counted lifetime management avoid this by cleaning themselves up when all references to them have been released.
But since TStringList isn't a COM object, you cannot enjoy the convenience this offers.
Fortunately there is a way to use COM reference counting to take care of these things without have to create all new, COM versions of the classes you wish to use. You don't even need to switch to an entirely COM based model.
I created a very simple utility class to allow me to "wrap" ANY object inside a lightweight COM container specifically for the purpose of getting this automatic cleanup behaiour. Using this technique you can replace the above example with:
procedure SomeStringsOperation(const aStrings: TStrings);
var
list: TStringList;
begin
AutoFree(#list);
list := TStringList.Create;
:
// do some work with "list"
:
end;
The AutoFree() function call creates an "anonymous" interfaced object that is Release()'d in the exit code generated by the compiler for the procedure. This autofree object is passed a pointer to the variable that references the object you wish to be free'd. Among other things this allows us to use the AutoFree() function as a pseudo-"declaration", placing any and ALL AutoFree() calls at the top of the method, as close as possible to the variable declarations that they reference, before we have even created any objects.
Full details of the implementation, including source code and further examples, are on my blog in this post.
The memory management of interfaces is done through implementation of _AddRef and _Release which are implemented by TInterfacedObject.
In general using interfaces to make memory management less cumbersome can be a nice idea, but you need to take care of these things:
Make sure the classes that implement interfaces are derived from TInterfacedObject or roll your own ancestor class that provides good implementations for _AddRef and _Release
Use either/or: so either user interfaces references, or use object instance references, don't mix them. That can be problematic when implementing interfaces in components (as those derive from TComponent, not TInterfacedObject)
Don't go the TInterfacedComponent way as that mixes Owner based memory management and _AddRef/_Release based memory management
Watch circular interface references (you can go around implementing "weak interface references" mentioned here and implemented here)
You need to maintain extra code as you need to define interfaces for the parts your classes that you want to expose, and keep those two in sync (you could Model Maker Code Explorer for this; it allows you to extract interfaces and in general boost your development because it manages the interface/implementation parts of code in single-actions)
You need some extra plumbing to create instances of the underlying classes. You can use the factory pattern for that.
That is not always effectively, but does answer a few of your underlying questions.
Shortest possible answer: The default delphi memory model is that owners free the objects they own. All other references are weak references and must let go before the owner does. "Sharing" an object that has a lifetime shorter than the entire lifetime of the app is rarely done. Reference counting is rarely done, and when it is done, it is only done by experts, or else it adds more bugs and crashes than it solves.
Learn idiomatic delphi style and try to imitate it, don't fight the grain. Sadly, people think that "program against interfaces, not implementations" means "Use IUnknown everywhere". That's not true. I recommend you don't use COM IUnknown interfaces, and use abstract base classes instead. The only thing you can't do is implement two abstract base classes in a single class, and the need for that is rare.
Update: I've recently found it helpful to use COM Interfaces (IUnknown based) to help me separate out my model and controller implementations from my UI classes. So I do find using IUnknown based interfaces useful. But there is not a lot of documentation and prior art out there to base your efforts on. I'd like to see a "cookbook" style recipe that lays all this out for people, so they can work without the usual problem of combining interface and non-interface based lifetime management, and all the trouble that comes while you get used to that extra complexity.
Switching to interfaces only for avoiding manual Free's is senseless. Little economy in Free/try-finally lines will hardly compensate the necessity of declaring both g/setters and properties in the interface not mentioning the necessity of keeping the intf/class declarations in sync. Interfaces also bring performance loss due to implicit finalize code and reference counting. If performance is not the main point and all you want to achieve is autofreeing, I'd recommend using some universal interface wrappers like the one Deltics suggested.

Stop client code from freeing shared objects in Delphi

I have implemented the FlyWeight pattern in my Delphi application. Everything has worked great, everything is a lot faster and takes less memory, but there is one thing I am worried about.
My implementation will only work as long as client code never calls Free() on the shared objects. In the Flyweight pattern, the FlyweightFactory itself is supposed to "maintain a reference to flyweights" i.e. to the shared objects.
My problem is that there is no (obvious) way to stop other code from destroying the objects once they have a reference. I could live with this, but it would be a "big win" if I could pass these objects round freely without worrying about accidental freeing.
To show a (contrived) example:
flyweight1:=FlyweightFactory.GetFlyweight(42);
WriteLn('Description is '+flyweight.Description);
flyweight1.Free;
flyweight2:=FlyweightFactory.GetFlyweight(42);
WriteLn('Description is '+flyweight.Description);
// Object has already been Freed!; behaviour is undefined
I have considered overriding the destructor as shown here to stop the flyweight object being freed altogether. This is not an option in my case as
a) I only want to stop cached objects from being Freed, not objects that aren't part of the cache. There is a lot of legacy code that doesn't use the cache; they still need to create and free objects manually.
b) I do want the FlyweightFactory to Free the objects during finalization; I agree with Warren P that a "zero leaked memory" policy is best.
I'll leave with a quote from the Flyweight chapter of GoF
Sharability implies some form of
reference counting or garbage
collection to reclaim storage when
it's no longer needed. However,
neither is necessary if the number of
flyweights is fixed and small. In that
case, the flyweights are worth keeping
around permanently.
In my case the flyweights are "fixed" and (sufficiently) small.
[UPDATE See my answer for details of how I solved this problem]
My answer to the question you link to still applies. The objects must know by means of a private boolean flag that they are cached objects. Then they can elect not to destroy themselves in Destroy and FreeInstance. There really is no alternative if you want to allow Free to be called.
To deal with finalization you would want to add the cached objects to a list of cached objects. That list of objects can be freed at finalization time. Of course the flag to disable freeing would have to be reset whilst you walked the list.
Having made this point regarding finalization, I would advise you to register an expected memory leak and just leak this memory. It makes the code much simpler and there's nothing to lose. Any memory you don't free will be reclaimed by the OS as soon as your executable closes. One word of caution: if your code is compiled into a DLL then leaking could be troublesome if your DLL is loaded, unloaded, loaded again etc.
What all this is telling you is that you are swimming against the current. Is it possible that you could achieve your goals with a different solution that fitted better with the way Delphi is steering you?
I suggest to add a reference count in order to known if your shared object is still used.
Every client should use the pattern AddRef / Release (AddRef increases the count; Release decrements it; if count reaches zero Free is called)
The AddRef may be called directly by your GetFlyweight method; Release has to be used instead of Free.
If you refactor your class and extract an interface from it the AddRef/Release pattern in naturally implemented in then interface implementation. (You could derive from TInterfacedObject or implement IInterface by your self)
Ideally you seldom want 2 ways of using the same things. It just complicates matters in the long run. In 6 months time, you might not be sure whether a particular piece of code is using the new flyweight paradigm or the old paradigm.
The best way to prevent someone calling Free or Destroy is to make sure it's not even there. And within the Delphi world, the only way to do that is to use interfaces.
To expand on your contrived example:
type
TFlyweightObject = class
public
constructor Create(ANumber: Integer);
function Description: string;
end;
TFlyweightFactory = class
public
function GetFlyweight(ANumber: Integer): TFlyweightObject;
end;
This being an object can easily be destoyed by a rogue client. You could make the following changes:
type
IFlyweight = interface
//place guid here
function Description: string;
end;
TFlyweightObject = class(TInterfacedObject, IFlyweight)
public
constructor Create(ANumber: Integer);
function Description: string;
end;
TFlyweightFactory = class
public
function GetFlyweight(ANumber: Integer): IFlyweight;
end;
Now any code that is updated to use the flyweight paradigm is forced to use it as intended. It's also easier to recognise the old code that still needs to be refactored because it doesn't use the interface. Old code would still construct the "flyweight" object directly.
You could also hide a destructor by making it protected or private. Programmers won't see it outside the scope of the unit in which it is declared in.
But I am posting this answer more like a curiosity because this will not prevent freeing an object by using FreeAndNil or by using a "Protected Hack"
I managed to get around the problems I cited in my original question using the following techniques, suggested by David Heffernan in his answer.
a) I only want to stop cached objects
from being Freed, not objects that
aren't part of the cache. There is a
lot of legacy code that doesn't use
the cache; they still need to create
and free objects manually.
I fixed this by subclassing the Flyweight class and overriding destroy, BeforeDestruction and FreeInstance in the subclass only. This left the parent class as is. The cache contains instances of the subclass (which can't be freed), whereas objects outside the cache can be freed as per usual.
b) I do want the FlyweightFactory to
Free the objects during finalization;
I agree with Warren P that a "zero
leaked memory" policy is best.
To solve this, I added a private boolean flag that has to be set to true before the object can be freed. This flag can only be set from the Cache Unit, it is not visible to other code. This means that the flag cannot be set outside by code outside the cache.
The destructor just looks like this:
destructor TCachedItem.destroy;
begin
if destroyAllowed then
inherited;
end;
If client code trys to Free a cached object, the call will have no effect.

What are the pros and cons of using interfaces in Delphi?

I have used Delphi classes for a while now but never really got into using interfaces. I already have read a bit about them but want to learn more.
I would like to hear which pros and cons you have encountered when using interfaces in Delphi regarding coding, performance, maintainability, code clearness, layer separation and generally speaking any regard you can think of.
All I can think of for now:
Pros:
Clear separation between interface and implementation
Reduced unit dependencies
Multiple inheritance
Reference counting (if desired, can be disabled)
Cons:
Class and interface references cannot be mixed (at least with reference counting)
Getter and setter functions required for all properties
Reference counting does not work with circular references
Debugging difficulties (thanks to gabr and Warren for pointing that out)
Adding to the answers few more advantages:
Use interfaces to represent the behavior and each implementation of a behavior will implement the interface.
API Publishing: Interfaces are great to use when publishing APIs. You can publishing an interface without giving out the actual implementation. So you are free to make internal structural changes without causing any problems to the clients.
All I say is that interfaces WITHOUT reference counting are VERY HIGH on my wishlist for delphi!!!
--> The real use of interfaces is the declaration of an interface. Not the ability for reference counting!
There are some SUBTLE downsides to interfaces that I don't know if people consider when using them:
Debugging becomes more difficult. I have seen a lot of strange difficulties stepping into interfaced method calls, in the debugger.
Interfaces in Delphi come with IUnknown semantics, if you like it or not, you'r stuck with reference counting being a supported interface. And, thus, with any interfaces created in Delphi's world, you have to be sure you handle reference counting correctly, and if you don't, you'll end up with leaks. When you want to avoid reference counting, your only choice is to override addref/decref and don't actually free anything, but this is not without its own problems. I find that the more heavily interface-laden codebases have some of the hardest-to-find access violations, and memory leaks, and this is, I think because it is very difficult to combine the refcount semantics, and the default delphi semantics (owner frees objects, and nobody else does, and most objects live for the entire life of their parents.).
Badly-done implementations using Interfaces can contribute some nasty code-smells. For example, Interfaces defined in the same unit that defines the initial concrete implementation of a class, add all the weight of interfaces, without really providing proper separation between the users of the interfaces and the implementors. I know this isn't a problem with interfaces themselves, but more of a quibble with those who write interface-based code. Please put your interface declarations in units that only have those interface declarations in them, and avoid unit-to-unit dependency hell caused by glomming your interface declarations into the same units as your implementor classes.
I mostly use interfaces when I want objects with different ancestry to offer a common service. The best example I can think of from my own experience is an interface called IClipboard:
IClipboard = interface
function CopyAvailable: Boolean;
function PasteAvailable(const Value: string): Boolean;
function CutAvailable: Boolean;
function SelectAllAvailable: Boolean;
procedure Copy;
procedure Paste(const Value: string);
procedure Cut;
procedure SelectAll;
end;
I have a bunch of custom controls derived from standard VCL controls. They each implement this interface. When a clipboard operation reaches one of my forms it looks to see if the active control supports this interface and, if so, dispatches the appropriate method.
For a very simple interface you can do this with an of object event handler, but once it gets sufficiently complex an interface works well. In fact I think that is a very good analogue. Use an interface where you a single of object event won't fit the functionality.
Interfaces solves a certain kind of issues. The primary function is to... well, ...define interfaces. To distinguish between definition and implementation.
When you want to specify or check if a class supports a set of methods - use interfaces.
You cannot do that in any other way.
(If all classes inherits from the same base class, then an abstract class will define the interface. But when you are dealing with different class hierarchies, you need interfaces to define the methods thy have in common...)
Extra note on
Cons: Performance
I think many people are too blithely dismissing the performance penalty of interfaces. (Not that I don't like and use interfaces but you should be aware of what you are getting into). Interfaces can be expensive not just for the _AddRef / _Release hit (even if you are just returning -1) but also that properties are REQUIRED to have a Get method. In my experience, most properties in a class have direct access for the read accessor (e.g., propery Prop1: Integer read FProp1 write SetProp1). Changing that direct, no penalty access to a function call can be significant hit on your speed (especially when you start adding 10s of property calls inside a loop.
For example, a simple loop using a class
for i := 0 to 99 do
begin
j := (MyClass.Prop1 + MyClass.Prop2 + MyClass.Prop3) / MyClass.Prop4;
MyClass.Update;
// do something with j
end;
goes from 0 function calls to 400 function calls when the class becomes an interface. Add more properties in that loop and it quickly gets worse.
The _AddRef / _Release penalty you can ameliorate with some tips (I am sure there are other tips. This is off the top of my head):
Use WITH or assign to a temp variable to only incur the penalty of one _AddRef / _Release per code block
Always pass interfaces using const keyword into a function (otherwise, you get an extra _AddRef / _Release occurs every time that function is called.
The only case when we had to use interfaces (besides COM/ActiveX stuff) was when we needed multiple inheritance and interfaces were the only way to get it. In several other cases when we attempted to use interfaces, we had various kinds of problems, mainly with reference counting (when the object was accessed both as a class instance and via interface).
So my advice would be to use them only when you know that you need them, not when you think that it can make your life easier in some aspect.
Update: As David reminded, with interfaces you get multiple inheritance of interfaces only, not of implementation. But that was fine for our needs.
Beyond what others already listed, a big pro of interfaces is the ability of aggregating them.
I wrote a blog post on that topic a while ago which can be found here: http://www.nexusdb.com/support/index.php?q=intf-aggregation (tl;dr: you can have multiple objects each implementing an interface and then assemble them into an aggregate which to the outside world looks like a single object implementing all these interfaces)
You might also want to have a look at the "Interface Fundamentals" and "Advanced Interface Usage and Patterns" posts linked there.

If everything implemented an interface, would this be garbage collection?

I'm still something of a newbie, and I know my thinking is incorrect; I just don't know where ...
Just about everything in Delphi is descended from TObject. What if everything instead descended from a TInterfaceObject that implemented some trivial interface (e.g., "INamable," with a single method that returned a class's name string)? Since TObject already has a property that returns a name string, you wouldn't need to add anything to additional classes.
In other words, a TInterfacedObject would inherit from TObject (or something high up in the hierarchy), and everything currently descending from TObject would now descend from this new class. Wouldn't this mean everything was now reference counted?
If you can spot where my knowledge is lacking, I'd love to learn. Thanks, as always -- Al C.
It's not clear whether you're asking:
Why didn't Borland do this, when they originally developed Delphi?
Why don't Embarcadero do this, in a future version of Delphi?
Why don't I do this, with my own user data types?
Wouldn't this mean everything was now reference counted?
Yes it would.
However, you don't necessarily want everything to be ref-counted: every little integer, every string, every boolean, every element in an array ... if for no other reason that the implementation of ref-counting adds some overhead, e.g. a little extra memory per object, perhaps insignificant for large objects but proportionally more significant if applied to every tiny object.
Also, see also Garbage Collector For Delphi Objects and Components which says (quote),
Delphi provides three ways of object management :
Create/destroy the objects using try..finally.
Use TComponent descendants - create a component and let its owner free it.
Interfaces - when the reference count for an interface becomes 0 the
object which implements it is
destroyed.
The Delphi help says you shouldn't mix
the TComponent owner approach with the
interface memory management, but ...
Would this be garbage collection?
Not quite; mere reference-counting isn't as robust as garbage-collection:
With reference-counting, if you have two reference-counted instances each holding a reference to the other, then they're not released automatically. To release them you would need to break this 'circular reference' (i.e. explicitly tell one of them to release its reference to the other).
With true garbage-collection, the garbage-collector would notice that those two istance aren't referenced from anywhere else, and release them both.
Update
If you annotate your potentially circular references as [weak] references, then they will get destroyed ok. But prior to Delphi 10.1 Berlin this only works in the NexGen compilers (i.e. those that use LLVM under the hood). From 10.1 Berlin onwards these [weak] references work everywhere.
It wouldn't be working garbage collection because interfaces use a very simple reference-counting system, and circular references, which are very common in Delphi code, break simple ref-counting.
No, because of two things:
Even if a class implements an interface it does not automatically make it reference counted. Only if you actually use it to implement that interface the reference counting will have any effect.
As others already said: Reference counting in interfaces will result in the class instance to be freed immediately when the reference count reaches 0. It is an implicit call to the Free method at that point in code. This will fail e.g. if two objects reference each other. True garbage collection will free the objects not when they go out of scope but when memory is needed, so there is no performance impact every time the reference count reaches 0 because the object will just continue to exist. In addition a good garbage collector will detect the isolated circular references (e.g. A references B references C references A but nothing else references any of these objects) and will free these objects as well.
Garbage collection is different from simple ref counting. You can have automatic deletion when a ref count reaches 0, but that too is not garbage collection. Garbage collection means letting go of your ability to control when things are deleted from memory, and allowing the underlying language's implementation to optimize the behviours. You stop paying attention to reference counts, and trust in the dynamic behaviours of a particular implementation of garbage collection.
Naturally, garbage collection uses a system of reference counting to know when something is no longer referenced, but that is a small piece of the puzzle.
Reference counting is a form of garbage collection, but not a very good one. It is used by some languages (python I think) although often with cycle detection.
Even if you descended from TInterfaceObject, the object is not reference counted and thus garbage collected unless you only use the interface reference and not the object reference.
I.e. you would need to use
Var
nameable: IMyInterface;
begin
nameable:= IMyInterface.Create();
nameable.x(y);
etc
end;
This implies that your interface needs to support already the methods and properies that you require which quickly becomes tedious as you need to create an interface for each class.
It can be done reasonably easily in D2009 or later though. See Barry Kelly's implimentation of smart pointers. The usual reference countng cavets apply though.

Resources