5
votes

I am a Java developer who has recently been thrust into wearing a Delphi developer hat.

As is typically the case in such situations, I wind up trying to do things in Delphi while still using my 'Java' mindset, and I get confounded when they don't work.

Today's issue is the notion of an interface. In Java, I can define an interface, give it some methods, and later declare a class that implements that interface.

I have tried to do the same thing in Delphi, and got my fingers burned. I declared an interface that extended IInterface. But when it came time to implement that interface, I was greeted by a number of unimplemented methods errors for methods I didn't declare (QueryInterface, _AddRef, _Release).

A little Google told me that I needed to extend the TInterfacedObject instead of TObject. This made me uneasy because it suggests that I cannot simply add an interface to some third-party class unless that class ultimately extends TInterfacedObject.

But now, when it becomes time to set my interfaced object .Free, I'm getting EInvalidPointer exceptions.

As a result, I'm beginning to conclude that the word interface means something completely different to a Java developer, and a Delphi developer.

Can someone who is proficient at both languages enlighten me as to the differences?

Cheers.

2
At a high level, interface means the same in both languages. There are implementation detail differences. Clearly you are getting the implementation wrong in the Delphi code. We could tell you what you were doing wrong if you showed code.David Heffernan

2 Answers

8
votes

Interface types in Delphi have three functions:

  1. Be a general language feature for abstracting interface from implementation a la interface types in Java.
  2. Form the core of Delphi's COM support (a Delphi IInterface is the same as the COM IUnknown).
  3. Provide a form of automated memory management in the context of a non-garbage collected environment.

These functions are conceptually distinct, and as you have found, produce a less than optimal result when combined in the same feature:

  • Every interface in Delphi must ultimately descend from IInterface/IUnknown, and as such, have the three IUnknown methods (AddRef, Release and QueryInterface - the first two are renamed _AddRef and _Release in Delphi to discourage you from calling them directly). If you want to be able to query for an interface at runtime, you also need to give it a GUID.
  • TInterfacedObject exists as a convenient base class, though you don't have to use it if you implement _AddRef, _Release and QueryInterface yourself (doing so involves a standard pattern, so it isn't hard). In principle, you can also disable reference counting by returning -1 for the first two (the TComponent class does this, for example).
  • Nonetheless, the compiler will always insert _AddRef and _Release calls when an object is accessed via an interface. This makes it frequently unsafe to access the same object through an object and interface reference even when _AddRef and _Release just return -1.
3
votes

The difference is in garbage collector. Java has one. But in Delphi you have to control your objects by yourself.

_AddRef and _Release created to make this little easy. When a variable begins to point to your object, Delphi calls _AddRef. There you have to increase counter of references to that object. When variable in your code "loose" link to object Delphi calls _Release. There you have to decrease counter. When your counter become 0 then you can call destroy() for this object Self.Destroy().

Hope this helps.

PS. TInterfacedObject already implements these methods, that is why Google and Delphi documentation advise to use TInterfacedObject.