From 9220126724199058392
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,a052d2220d0eb455,start
X-Google-Attributes: gidf78e5,public
X-Google-ArrivalTime: 1995-03-06 10:11:22 PST
Path: bga.com!news.sprintlink.net!howland.reston.ans.net!news.moneng.mei.com!uwm.edu!news.alpha.net!news.mathworks.com!panix!not-for-mail
From: tmurphy@panix.com (Timothy Murphy)
Newsgroups: comp.std.c++
Subject: Name.Hiding.die.die.die
Date: 6 Mar 1995 12:57:25 -0500
Organization: PANIX Public Access Internet and Unix, NYC
Lines: 101
Message-ID: <3jfie5$ltl@panix3.panix.com>
NNTP-Posting-Host: panix3.panix.com
X-Newsreader: TIN [version 1.2 PL2]


Name Hiding: Threat or Menace?

Timothy S. Murphy   5 March 1995.


  A few observations and proposals regarding the C++ language standard.
The last draft specification (DS) I looked at was dated 20 September 1994;
I also refer to the ARM.

   Please rip this apart, both with your editor and your words; I am
very interested in feedback, particularly from members of the standards
committee.


   I was very disappointed to read in [DS 13.1.1] that the name-hiding
rule is still with us.  You probably are familiar with it: A function
declared in a derived class (or declared inside another function) hides
all functions having the same name in all base classes (or functions
of the same name in nonlocal scope), regardless of their argument types.

   I must confess that I hate this rule and ask those who feel otherwise
to excuse my flippancy and (please) to send me some email (posting if
appropriate) eliciting its merits.


   The only argument in its "favor" that I have ever seen is in [ARM 13.1].
It says, in essence, that in a deep inheritance heterarchy a programmer
may not be aware of all the functions "above" the class they are
working in and, in the absence of the hiding rule, might inadvertently
invoke a function defined in a base class.

   I find this argument offensive.  Refinement of interface through
derivation is absolutely idiomatic to C++.  Inheriting from a class
without complete knowledge of its interface is ludicrously bad practice
and is in no way deserving of language support.

   Protecting people from their own ignorance has never been a design
objective of C++; rather its overall philosophy has been one of terseness,
orthogonality, and permissiveness.  It generally allows the programmer
to specify most any operation in a reasonable, obvious fashion, it
assumes always that programmers know what they want, and it provides
many mechanisms in the support of code re-use.  The name-hiding rule flies
in the face of all these tenets.


   In practice, name hiding applies to the public interface to a class
and most often to virtual functions.  Name clashes in the protected
or private parts of a class are symptomatic of inheriting from instantiable
classes, a practice which I am far from alone in finding questionable
and which, at a minimum, does not require the same level of language support
as does inheritance of interface.  The latter is of course the _only_
means of run-time polymorphism provided by C++.

   An easily understood example which hurt me recently is as follows.
I needed a heterarchy, all the classes in which were to provide a "clone"
function that returns a pointer to a copy of the object on which it
was invoked, the type of the pointer being the same as the type of the
pointer through which clone() was called.  That is:

   class C : public A, public B {...};
   C c;
   B *bp = &c;
   B *bpp = bp->clone();

   bpp is a B* , now pointing to a copy of c (a C) on the heap.  In the
presence of a truly correct implementation of virtual function return type
overriding [ARM 10.2], one could simply have a single virtual function
clone() whose return type is exactly that of the declaring class;
instantiable "leaf" classes provide the implementations and that's it.

   Unfortunately, to my knowledge, such compilers do not exist (the
implementation is tricky in the presence of multiple and/or virtual
inheritance on the return types) and probably will not exist for some
time.  As a compromise, I put in a dummy argument of the same type
as the return type (e.g., B's clone takes an unused B*) to separate
the functions.  In the absence of the name-hiding rule, a class need
only override the clone() methods of its immediate parents and you'd
be done (assuming inline definitions of these virtual functions, a smart
compiler could do the obvious folding) but in the presence of this
most odious rule, one must redefine clone() methods for the entire
heterarchy above you in _every_ single class (not even just the instantiable
classes) or, alternatively, to manually mangle up unique names for this
method in every class.  Either of these approaches leads to irrelevant
mental overhead and wasted keystrokes.  This is the kind of thing
I thought C++ was supposed to help us avoid :-(.


   Even in the presence of a perfect compiler, I have been thwarted by
the name-hiding rule though these examples take longer to describe in detail.
A multi-keyed lookup table placed in a highly refined container heterarchy
is a representative example.

   Is there a _real_ argument in support of the name hiding rule?
I'd love to see it.


-- Timothy S. Murphy: A serious user and admirer of C++.
   tmurphy@panix.com




