Topic: Name.Hiding.die.die.die


Author: jamshid@ses.com (Jamshid Afshar)
Date: 10 Mar 1995 00:52:21 GMT
Raw View
In article <3jfie5$ltl@panix3.panix.com>,
Timothy Murphy <tmurphy@panix.com> wrote:
>   Please rip this apart, both with your editor and your words; I am
>very interested in feedback, particularly from members of the standards
>committee.

Please read Stroustrup's _Design and Evolution of C++_.  That should
be the first resource used when wondering why some apparently bad rule
exists in C++.

>   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" [...]

D&E 3.5.3 discusses this to a larger extent, gives an historical
account with bad experiences using your alternative, and points out
that this rule is a natural consequence of usual scope rules (names in
a new scope hides the same name in outer scopes).  Finally, it gives
an easy way to allow base functions to overload derived versions by
inserting the new "using" directive in the derived class.

>   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();

Differing return types is a completely separate issue from overloading
and name hiding (you can't overload a function with only a different
return type).

>   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.

The rule you're describing was added by the ANSI/ISO committee.  Does
your version of the ARM discuss it (mine doesn't)?

>   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.

I know Borland at least a couple of others have implemented this rule
for quite a while:

 struct B { virtual B* f(); };
 struct D : B { virtual D* f(); };  // overrides B::f

>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 :-(.

It seems like you're asking for covariance, but that would not be
type-safe.

>   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

I highly recommend D&E to you.

Jamshid Afshar
jamshid@ses.com




Author: mat@mole-end.matawan.nj.us
Date: Wed, 8 Mar 1995 07:21:49 GMT
Raw View
In article <3jfie5$ltl@panix3.panix.com>, tmurphy@panix.com (Timothy Murphy) writes:
>
> 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 decline to do so, partly because it is rather late, and partly because
this issue has been visited before.

It probably won't be enough to say that your way was tried, and was found
severely wanting.  In fact, most people think of doing it that way, and
it was only experience with doing it that way that led to the current rule.
--
 (This man's opinions are his own.)
 From mole-end    Mark Terribile
 mat@mole-end.matawan.nj.us, Somewhere in Matawan, NJ
 (Training and consulting in C, C++, UNIX, etc.)




Author: tob@world.std.com (Tom O Breton)
Date: Mon, 6 Mar 1995 22:10:01 GMT
Raw View
tmurphy@panix.com (Timothy Murphy) writes:
>    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.

I used to have mixed feelings about name-hiding, but now I think it's a
good idea.

I once felt that since an overloaded function of the same name is
semantically an entirely _different_ function, that name-hiding amounted
to cross-talk upon accident of having the same name.

But now I feel that overloading where one overloaded version might
"capture" arguments intended for another makes it too dangerous:

        base::foo( short i );
        derived::foo( long i );

        foo( 100 ); //Should base capture this? I say it shouldn't be
                    //risked.

I could be persuaded that it's only neccessary to hide functions with
the same number of arguments, including all combinations of default
arguments, though the rule seems a bit complex and doesn't accomplish
anything that some editing can't,

        Tom

--
tob@world.std.com
TomBreton@delphi.com: Author of The Burning Tower





Author: chris@alofi.etca.fr (Christian Millour)
Date: 7 Mar 1995 11:13:22 GMT
Raw View
In article <3jfie5$ltl@panix3.panix.com>, tmurphy@panix.com (Timothy Murphy) writes:
|>
|> Name Hiding: Threat or Menace?
|>
|> Timothy S. Murphy   5 March 1995.
|>
<< ... the name hiding rule should die ... >>
|>
|> -- Timothy S. Murphy: A serious user and admirer of C++.
|>    tmurphy@panix.com
|>
|>

I second that fully.

I went into exactly the same process, was similarly bitten by the rule
and similarly unconvinced (read horrified) by its motivation.

IMO people should think in terms of function signatures, not function
names, and the rule should be turned into an optional warning.
This won't break existing code.

--chris@etca.fr
Le monde entier est un cactus, il est impossible de s'asseoir (J. Dutronc)








Author: chris@alofi.etca.fr (Christian Millour)
Date: 7 Mar 1995 11:16:17 GMT
Raw View
In article <D51HKq.1on@world.std.com>, tob@world.std.com (Tom O Breton) writes:
|> I used to have mixed feelings about name-hiding, but now I think it's a
|> good idea.
|>
|> I once felt that since an overloaded function of the same name is
|> semantically an entirely _different_ function, that name-hiding amounted
|> to cross-talk upon accident of having the same name.
|>
|> But now I feel that overloading where one overloaded version might
|> "capture" arguments intended for another makes it too dangerous:
|>
|>         base::foo( short i );
|>         derived::foo( long i );
|>
|>         foo( 100 ); //Should base capture this? I say it shouldn't be
|>                     //risked.

Can you provide a concrete example of an interesting use of the above
construct ?

--chris@etca.fr

|> --
|> tob@world.std.com
|> TomBreton@delphi.com: Author of The Burning Tower
|>




Author: tmurphy@panix.com (Timothy Murphy)
Date: 6 Mar 1995 12:57:25 -0500
Raw View
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