7
votes

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.

5

5 Answers

8
votes

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 :

  1. Create/destroy the objects using try..finally.
  2. Use TComponent descendants - create a component and let its owner free it.
  3. 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.

5
votes

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.

3
votes

No, because of two things:

  1. 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.
  2. 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.
2
votes

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.

1
votes

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.