All of your points above are quite valid (if perhaps a bit over stated), but I’m going to disagree on the COM baggage - yes - interfaces were added to enable com support, but they are not tied to com - you don’t need a type library or any registration etc for objects that implement interfaces. I see this FUD trotted out every time interfaces are discussed. If you are using interfaces that does not mean you are using COM.
Yes, _AddRef and _Release are part of IUnknown - which is a com interface, but they enable reference counting memory management which is one of the many benefits of using interfaces.
Like any other language feature in any programming language - you need to learn how to use them and understand the benefits and issues with the feature to make an informed decision.
COM baggage is exactly the terminology used by Marco Cantú when I questioned him why they just don’t remove this (let’s call it) annoyance from Delphi interfaces.
BTW, I never mentioned type libraries or I never said that interfaces means that you are using COM. But you do need to implement 3 useless methods because of the way interfaces were born strictly connected to COM (translation: they carry a COM baggage, IMO).
Whilst I would love to see an interface type that doesn’t implement reference counting (so the compiler doesn’t insert calls to addref and release) - I don’t see that as baggage - it’s a useful feature.
Some devs have an irrational fear of com - so when people say interfaces is com baggage - they are dissuaded from using them.
To me this is not so much a “con” of interfaces but of their design. Plus, there is a way to make a default implementation method but I am not going to talk about it because it’s unclear to me whether it is intended (and can therefore be relied upon long-term) or it’s not intended, in which case at any point in time your code could break and you’d be in trouble.
Are we really talking about bytes here? Seriously? Also, again, design matters. If your interfaces are designed the way they should, this should not be a problem.
I don’t disagree with this, but I have rarely ever had a need to do this.
I am not sure what you’re trying to say here. Would you mind to be more specific?
One thing I always do for my interfaces is to either have an enumerator or a ForEach method with anonymous procedure and function calls. This makes the need for virtual getters and setters basically go away.
I quite like the fact that you can’t mix things, in fact. I know it’s not great from a coding perspective, but from the design perspective it forces you to really think about what you’re doing. Besides, there are ways to do this (indirectly) if you really need to, but you should never do it even if it were allowed.
I disagree. While it’s true that interfaces were introduced with COM and while it’s true that they retain those support methods, today’s interfaces aren’t tied to com.
IUnknown is an alias for IInterface nowadays and has been so for quite some time.
Yes, I am. Why? Maybe you never developed an application that needs to handle millions of object instances at once, where every byte counts. But the fact that you doesn’t know it doesn’t make it inexistent, right?
I can’t remember using it as an integral design aspect of my code but I know I’ve relied on it to peek behind the curtain so to speak in unit tests, logging code and temporary debugging solutions. In that sort of limited, non-crucial use scenario I think it has a place.
I wrote about the improvements that I made in Spring4D which eliminated all virtual methods behind the collections in my blog post some while ago. So the effect is real but the funny thing is: every time you have been using a try finally somewhere you suffered from the very same effect until Delphi 10.4.2! See this issue: Log in - Embarcadero Technologies - did anyone ever think of not using try/finally because of that?
The case of using up instance size for the interface table pointers can be a real issue indeed and this was also something I worked on - implementing interfaces across multiple inheritance levels was a bad idea so I only implement them all on one class so the interfaces that inherit from each other are put into the same slot - all spring collection types should only ever consume SizeOf(Pointer)*2 space for that. To compare: RTL TList takes 44 bytes, an IList instance 56 bytes on 32bit, the numbers for 64bit are: RTL 88 bytes and Spring 104 bytes.
If you have millions of object instances you probably don’t want them to implement objects which would be wrong anyway I would guess as they are probably just data-holding objects and thus don’t need to be handled via interfaces (see Nick Hodges DI book on creatables vs injectables). If these objects however have lists the thing might be different. But then it depends on how many items there are actually in those lists - if it’s just a handful then the overhead for those list instances is major and you might rather use a dynamic array (which also has some small overhead you know).