Restricting Overriding (was: More On Multiple Inheritance)
Matthew Tuck
matty@box.net.au
Tue, 06 Apr 1999 21:24:57 +0930
>> But anyway, one option would be to put a "final" on types (and you can
>> only have one impl), which would avoid getting around it via
>> delegation. This is essentially moving the Java solution into the
>> multi-impl world. However, I don't like this at all, I've encountered
>> final classes I really want to override before.
> Putting "final" on a type may really be strangulation. But I don't
> demand this. I just want to make sure that *some* of my methods don't
> get overridden if called from code within *my* class. What the subtype
> designer does in his class is not my business, I won't interfere. He may
> override as often as he wishes, but he should please not affect my code.
D'oh! I meant putting on a final on impls.
Anyway, to prevent overriding it is enough to make it private or final.
Since it can never be dynamically dispatched to, all the "override"s I
can think of may as well be defined as another (possibly non-final)
method in the subimpl.
>> Often what the author really wants is to restrict overriding of their
>> implementation. Hence they won't care if you write a whole new
>> implementation.
> That really would break the spirit of OOP. No one would want to restrict
> overriding as long as it's *safe*. That's the point.
Why would it? OOP is partly about contract, and if the impl designer
wants to ensure the code works in exactly that way, it's their right, in
exactly the same way as they can refuse access to a member. You don't
do a final unless there's a good reason for it.
You're perfectly entitled to write another impl not based upon this if
you don't like the terms and conditions.
>> Other sorts of override modifiers are possible as well - prefix only,
>> suffix only, surround only, etc. CLOS does something like this with its
>> overriding.
> This would be useful for message handlers. Often they simply add their
> own code to the standard impl.
Indeed. I have been writing some code recently that involved an
Approval Cycle for a document being approved from person to person. It
was object oriented in the sense that it had a top-level, then
subclassed by an approval structure (e.g. from A->B->C or A->B AND A->C
then D waiting on B & C), then for the specific document database and
then for the specific document type.
Essentially I often wanted to write final methods, since I was defining
a framework. Also, I often wanted to restrict overriding in different
ways such as prefixing.
Think of it this way. I know it has to be used that way. It doesn't
make sense otherwise. Hence, when I subimpl it, I want to know if I
use it wrong. What if I accidentally override the wrong method? Forget
to dispatch to the parent method at the end of the overridden method?
>> Can you think of any examples where you've wanted to use final?
> Not really, but maybe that's just because I haven't written many classes
> that are intended to be used by others.
Information hiding is useful even for one person.
> To a great extent I'm feeling
> uncomfortable with your opinion because it reduces (if not to say
> destroys) locality of code. If you can't tell any longer how something
> might work by looking at it and the parts it expressly uses because you
> can't prevent some unknown client to change its operation (for himself
> and his clients) in some arbitrary manner, you'd have to consider at lot
> more code to find bugs. I consider that a huge drawback.
I'm fully in favour of impl final, and always have been. I just think C
virtual is silly in the way it works, and that final isn't always
enough.
>> The situation I've discovered is you have certain methods, but you only
>> want to call them in a certain way, order, etc, so you make the driver
>> method final.
>> One language enhancement that would therefore be quite useful would be
>> the ability to override a method, but not to be able to call it.
>> Abstract methods could be filled in quite fine by the subimpl, but the
>> only way you could get to run those methods would be through actually
>> calling the driver method.
> Can you give an example? I think I understand what you mean, but I can't
> think of a situation where I would want to prevent the programmer from
> calling his own methods.
> BTW. a user could easily bypass this restriction if he wants to: He
> simply writes a method with an innocent name (that is not restricted)
> and calls that from the restricted method (which he is entitled to
> override). And since he may call his own method which does the same as
> the restricted one, viola...
I did a quick hunt for an example and couldn't find one, but you'd want
to do this where the overridden method calls back the subimpl. You're
right, you could get around it (which might or might not be OK). To get
this sort of protection you might need to actually restrict which
methods can call which methods which might well be a bit much. I'll
think a bit more about this one and see if I can find some examples.
> That definitely is a problem, but I see no reason why we shouldn't change
> this. The Eiffel approach to this lookes pretty flexible to me, for
> example.
I don't recall anything about Eiffel in this domain, can you elaborate?
>> The problem is the parent impl and subimpl might not be written by the
>> same person. The parent impl might be obfuscated, or beyond your
>> access. And there is often no reason for the keyword to be there in
>> the first place. If you shouldn't be overriding the method, ok, but it
>> can often be done just for efficiency. Non-overridable methods are the
>> exception rather than the rule in my experience.
> If you don't have access to the parent impl how can you be sure that your
> overriding method does everything correctly?
Sorry, write access.
> If the parent impl author marked it explicitly as "virtual" however, you
> can be pretty sure that he took your possible overriding into account.
Same for final, but in a better way.
> IMO it is better designed if the parent
> author provides virtual "hooks" that you may or may not override (he may
> provide a default function). This way can can make sure that his vital
> code always gets executed.
I agree - I use this technique extensively. My real qualm with virtual
(I just realised) is that the subimpl writer can write the method
without realising that it won't be dynamically dispatched to. Final
doesn't allow this possible bug.
> Another possibility for the parent impl author is to restrict access to
> all critical parts of the system. Maybe that is even better because (if
> designed right) you can easily see where an overriding might possibly
> occur. If designed right, it's more flexible as well, but optimisation
> will be more difficult.
Can you elaborate on what you mean by this?
--
Matthew Tuck - Software Developer & All-Round Nice Guy
mailto:matty@box.net.au (ICQ #8125618)
Check out the Ultra programming language project!
http://www.box.net.au/~matty/ultra/