🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c++
Article #840

Re: overloading vs. virtual functions

#840
From: Chip Salzenberg
Date: Wed, 20 Feb 1991 19:57
115 lines
6105 bytes
According to craig@gpu.utcs.utoronto.ca (Craig Hubley):
>The fact that C++ implements the two mechanisms [virtual functions and
>overloaded functions] so as to create (in my opinion) counter-intuitive
>effects is (in my opinion) a flaw in C++.  That is, the programmer must
>be very much aware of the "seam" between compile-time and run-time ...

This fact is a *necessary* consequence of one of C++'s design goals,
namely, that a programmer never pay more in efficiency than necessary.
That means that it is the programmer who decides when to use run-time
binding (virtual) and when to use compile-time binding (overloading).
If you remove the distinction, you remove the control -- a tradeoff
that is, to me, unacceptable.

>Consider how static initialization works in C++.  The initialization
>syntax means that some functions consist entirely of initialization
>and calls to these can (in principle) be resolved entirely at compile-
>time if they are called with static arguments.

Not so!  Those initializations cannot, even in principle, be resolved
at compile time if the actual types of their reference or pointer
parameters are unknown at compile time -- which is exactly the
situation for which virtual functions were created.  So your scenario
is only true in a "(C++)--" language without virtual functions.
That's one way to merge two features: get rid of one of them.  :-)

>>a base class B and a derived class D:
>>
>>    extern void foo(B&);
>>    extern void foo(D&);
>>    D d; B& b = d; foo(b);
>>
>>It is the "foo(B&)" function that will be called ...
>>
>>    D d; B& b = d; b.foo();
>>
>>It is B::foo() that is called ...
>
>In neither of the cases above can the system be expected to read the
>programmer's mind and "decide" to call the function associated with
>the "real" rather than the "formal" type.  In fact, C++ explicitly uses
>the -> vs. . notation so that the programmer can make that decision
>him/herself.

The notation is irrelevant.  Given a pointer "a" with member "b",
"a->b" and "(*a).b" are exactly equivalent in all cases.  I suppose
you knew that; so what did you really mean?

>There is no "cast to the dynamic type" operator in C++ that would
>delay this decision until run-time.  You can't even find out what
>the type is.

That's a necessary result of the most basic type rules.  And there's
nothing special about overloaded functions in this context: normal
functions and non-virtual member functions are in exactly the same
boat.  If dynamic type loss is unendurable to you, then you're using
the wrong language, because it's not going away.

>You have a good analogy there, but what you are proving is that overloading
>is solving the same problem as member functions, but without the other half
>of its brain:  runtime resolution.  When you mix virtuals and overloading,
>things get scary ...

"Well, don't do that, then."

I would contend that, once virtual functions have been introduced into
a class hierarchy, the additional use of overloaded functions is the
design error to be corrected, not some presumed deficiency in C++.
The differences between these techniques is a tool, not a flaw.

As a practical implementation issue, it is obvious that non-friend
non-member functions are indefinite in number.  Presuming a vanilla
implementation of virtual functions, how can a newly created object
have a virtual function table containing the addresses of overloaded
functions that haven't even been compiled yet?

>But if "orthogonal" in this sense is supposed to mean "never interact
>at all" you are wrong.

But that's not what I meant, because that's not what the word means!
Compare the Jargon File 2.6.3:

orthogonal: [from mathematics] adj. Mutually independent;
   well separated; sometimes, irrelevant to.  Used in a generalization
   of its mathematical meaning to describe sets of primitives or
   capabilities which, like a vector basis in geometry, span the
   entire `capability space' of the system and are in some sense
   non-overlapping or mutually independent.  ...

A language may have templates or not, and it may have inheritance or
not; so the features are orgthogonal.  But of course they interact;
it's all one language.

>As a programmer, I couldn't care less at what point in the
>compile/link/load/run process these things are resolved, except
>where the language forces me to be aware of it.

Well, then, you're using the wrong language, or else you need to
change your thinking.  (No smiley here.)  If your mental view of the
type system does not include the distinction between compile time and
run time, then C++ is simply a bad match for the way you think.  As I
mentioned up front, the *design goals* of C++ simply cannot allow all
type resolution to be (conceptually) delayed until run time.  Such a
language wouldn't be C++ any more.

>Obviously you have to be aware of these subtle differences sometimes but
>inventing wholly different syntax for each situation is IMHO a mistake.

Virtual and non-virtual member functions use the same syntax; the only
difference is one keyword.  However, once you decide: "But I don't
want to use a member function," then you have stepped outside the
bounds of "same things," so you shouldn't expect "same syntax."
-- 
Chip Salzenberg at Teltronics/TCT      <chip@tct.uucp>, <uunet!pdn!tct!chip>
"It's not a security hole, it's a SECURITY ABYSS." -- Christoph Splittgerber
   (with reference to the upage bug in Interactive UNIX and Everex ESIX)
Technical Details
Message-ID: <27C2D4B8.3AD3@tct.uucp>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!zaphod.mps.ohio-state.edu!mips!daver!tscs!tct!chip
References: <1991Feb13.011731.10114@gpu.utcs.utoronto.ca> <27BFD8E3.3D1D@tct.uucp> <1991Feb19.051123.5198@gpu.utcs.utoronto.ca>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!zaphod.mps.ohio-state.edu!mips!daver!tscs!tct!chip
From: chip@tct.uucp (Chip Salzenberg)
Newsgroups: comp.std.c++
Subject: Re: overloading vs. virtual functions
Summary: Well, don't do that, then
Message-ID: <27C2D4B8.3AD3@tct.uucp>
Date: 20 Feb 91 19:57:44 GMT
References: <1991Feb13.011731.10114@gpu.utcs.utoronto.ca> <27BFD8E3.3D1D@tct.uucp> <1991Feb19.051123.5198@gpu.utcs.utoronto.ca>
Organization: Teltronics/TCT, Sarasota, FL
Lines: 115