[Qt-interest] Non-Virtual Interface Idiom
Oliver.Knoll at comit.ch
Oliver.Knoll at comit.ch
Tue Dec 21 11:03:05 CET 2010
Hello there ;)
On 2010-12-21 Herb Herb Sutter wrote:
>> ...
>> I think Herb Sutter did not understand the point of interfaces: he
>> mixes implementation with interfaces. When I talk about "interfaces" I
>> think "Java interfaces", and in C++ that renders to pure virtual
>> classes (in my understanding of "interfaces").
>
> First, the above was said to a C++ audience, and "interface" was used in the sense
> of "the public interface of a class" (i.e., not of a Java- or C#-style interface).
First off, I must apologise: yes, currently - unfortunately ;) - I am developing in Java in business, as you might have guessed, so my mind is geared toward that language currently. I was well aware that "interface" in the generic sense is off course the "contract" of any given class, but only 1 minute later when I sent the email I noticed my wrong focusing on "Java interfaces" (and yes, also in my current little C++ hobby Qt project I am dealing with "pure virtual interfaces" right now, so my mind is currently focused on that ;).
At that time I was hoping no one would notice my narrowing down to "Java interfaces" and that it would go unnoticed.
But Thiago already nailed me on that one ;)
Anyway, for the sake of this discussion we now talk about "interfaces" in your sense, as "contract" of any given class.
> ...
> languages. Briefly, interface methods should be thought of as being implemented,
> whereas virtual methods are overridden, and there is a difference. People often
> don't grok that distinction at first.)
To be honest that distinction might make a difference on a compiler level, and at runtime there might be some subtle (performance) differences on how these methods are looked up when calling. But from a "user" point of view (or "contractor") I don't think that really matters whether I call a method which is "implementing a (Java-) interface" or "overriding a virtual method (which happens to be pure virtual)". So most people don't really have to care about that, unless you are into compiler construction or programming language defintion.
What really matters is the contract as such, *what* this method does, what it *returns* and what it *expects*. In both cases - the Java implementation of the interface and the C++ case where I call a virtual method - I only know at runtime which method is *really* called (*), so from that point of view both implementations are equal: I know the contract and only at runtime it is decided which method is really executed (depending on the dynamic type of the instance).
(*) Okay, I only saw now that you also suggest to make the Java implementation 'final'.
>> But for interfaces this totally does not make sense to me,
>
> Right, it's about classes. That classes can choose to implement NVI is a
> significant advantage of classes over interfaces. However, in those environments
> you have to stick with interfaces most of the time because of the SI restriction.
I assume SI means Single Inheritance - let's keep that out for a minute, as to keep things simple - otherwise that would open whole new doors in the discussion ;)
> ...
> It's just good engineering to decouple two separate and independent things:
I agree on that :)
> (a) the interface presented to the outside world (callers)
Agree.
> (b) the customization hooks presented to derived classes (implementers)
> because they are different audiences with different needs.
That is where I disagree: for me the "virtual" part is/should be *also* part of the public interface: it tells the "contractor": "*Yes*, you *can* override this method, and it is safe to do so, when you stick to a, b and c conditions". So for me the 'virtual" here is a vital part of the contract! I don't see any practical reason why you want to separate this from the public part of the interface.
In your article you wrote: "It's better to not let publicly derived classes also customize the inherited interface, which is supposed to be consistent." I don't see why having the derived class only override private methods (and I must again admit that I had to look that up on why one wanted to make PRIVATE methods virtual: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.4 - this FAQ even quotes you, Herb ;) instead of the public methods more *consistent* - consistent in what?
Ok, let's agree on the following first: overriding is *dangerous*: I can break any base class when doing something stupid in the derived implementation; it does not matter whether I do that my overriding a public or private method. *However*, I absolutely agree that the Template Method makes it *less likely* that I break something, because the base class can control in which order the little tiny "worker methods" are called.
But for me that is a different discussion, this is all about the "fragile base class" problem, and when you say you want to make people more aware of this problem, then I agree, yes, it might make sense to promote the Template Method (to be honest I don't see right now how your pattern is "more restricted" than the actual Template Pattern, which I would have to look up in detail).
But just for the sake of "decoupling the interface from the fact that you can extend it"? I don't see why.
> ...
> Interfaces don't allow you to decouple them, and interfaces are best thought of as
> specifying base class public methods. That is, in Java and C#, it's good design to
> consider implementing interface methods using public _nonvirtual_
> (sealed/final) methods in the class that delegate to new nonpublic virtual methods.
I agree with you that deriving from classes is/can be dangerous, and I understand that your article tries to make people aware of this problem by proposing to always use a (restricted) Template Method pattern. But in my opinion that would be overdesign/over-engineering in simple cases where inheritance is really straight-forward and overriding a public method can't do much harm (at least not more than when you would override the equivalent private method in the NVI approach). Hence having your NVI pattern would introduce more code, hence less readability in many simple cases where the public method would do nothing more than simply call the private method, hence just one more indirection, but the same code being executed in the end.
The advantages that you mention like adding debug code, logging code are most often not needed.
Cheers, Oliver
--
Oliver Knoll
Dipl. Informatik-Ing. ETH
COMIT AG - ++41 79 520 95 22
More information about the Qt-interest-old
mailing list