[comp.lang.c++] renaming

budd@mist.cs.orst.edu (Tim Budd) (05/30/90)

When using inheritance, particularly multiple inheritance, it seems I often
miss the ability to do renaming, as in Eiffel.

Expanding on the syntax used to create pure virtual functions, it would be
nice to do something like the following:

class foo : public bar, pubic baz {
	...
	void gak(int i) = bar::geek;
	..
}

where geek is a method defined in bar which takes the same argument list as
gak.  As it stands, now I have to do something like the following

class foo : public bar, pubic baz {
	...
	void gak(int i) { bar::geek(i); }
	..
}

which is arguably no less readable, but does introduce the run-time
overhead of one additional function invocation.

lord@yellowsub.sgi.com (Tom Lord) (05/30/90)

In article <18591@orstcs.CS.ORST.EDU> budd@mist.CS.ORST.EDU (Tim Budd) writes:
>When using inheritance, particularly multiple inheritance, it seems I often
>miss the ability to do renaming, as in Eiffel.
>
>[...]  As it stands, now I have to do something like the following
>
>class foo : public bar, pubic baz {
>	...
>	void gak(int i) { bar::geek(i); }
>	..
>}
>
>which is arguably no less readable, but does introduce the run-time
>overhead of one additional function invocation.

This should have no extra overhead at all.  That is the point of 
inline functions.

Whatever system your language has for resolving `name clashes' in 
cases like this is definately going to be wrong.  Providing rename 
operators to sprinkle throughout declarations is quirky at best.
Writing code to resolve the abiguities is the most general, and simplest
solution.  Having your compiler do inline optimizations for this code
is a pretty good impementation strategy.

-t

steve@taumet.COM (Stephen Clamage) (05/31/90)

In article <18591@orstcs.CS.ORST.EDU> budd@mist.CS.ORST.EDU (Tim Budd) writes:
>	void gak(int i) { bar::geek(i); }
>introduce[s] the run-time overhead of one additional function invocation.

I know of no C++ compiler which would not inline this member function,
and it seems unlikely that any ever would refuse to do so.  It seems
unnecessary to introduce a new language feature, thus complicating *all*
compilers, to make things simpler for users stuck with bad compilers.

If your local C++ compiler won't inline such a simple function (meaning
no overhead whatsoever), try to get another one.  Such a compiler is
bound to be woefully deficient in other ways.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

jimad@microsoft.UUCP (Jim ADCOCK) (06/01/90)

In article <18591@orstcs.CS.ORST.EDU> budd@mist.CS.ORST.EDU (Tim Budd) writes:
>When using inheritance, particularly multiple inheritance, it seems I often
>miss the ability to do renaming, as in Eiffel.
>
>Expanding on the syntax used to create pure virtual functions, it would be
>nice to do something like the following:
>
>class foo : public bar, pubic baz {
>	...
>	void gak(int i) = bar::geek;
>	..
>}
>
>where geek is a method defined in bar which takes the same argument list as
>gak.  As it stands, now I have to do something like the following
>
>class foo : public bar, pubic baz {
>	...
>	void gak(int i) { bar::geek(i); }
>	..
>}
>
>which is arguably no less readable, but does introduce the run-time
>overhead of one additional function invocation.

There shouldn't be one additional function invocation in the example you
give, since gak(int i) is an inline function.  Try compiling and looking
at the code the following simple example generates.  On my system [as in
all C++ systems -- I think!] renaming causes no extra code to be generated.


extern "C" 
{
#include <stdio.h>
}

class BASE
{
public:
	virtual void Print();
};
void BASE::Print() { printf("BASE@ %lX\n",(long)this); }

class FOO: public BASE
{
public:
	void BASE_Print() { BASE::Print(); }
	void Print();
};
void FOO::Print() { printf("FOO @ %lX\n",(long)this); }

class BAR: public BASE
{
public:
	void Print();
};
void BAR::Print() { printf("BAR @ %lX\n",(long)this); }

class FOOBAR: public FOO, public BAR
{
public:
	void FOO_Print() { FOO::Print(); }
	void BAR_Print() { BAR::Print(); }
	void Print();
};
void FOOBAR::Print() { printf("FOOBAR @ %lX\n",(long)this); }

int main()
{
	FOOBAR foobar;
	foobar.BASE_Print();
	foobar.FOO_Print();
	foobar.BAR_Print();
	foobar.Print();

	printf("\n");

	FOOBAR* pfoobar = new FOOBAR;
	pfoobar->BASE_Print();
	pfoobar->FOO_Print();
	pfoobar->BAR_Print();
	pfoobar->Print();
}

roger@procase.UUCP (Roger H. Scott) (06/01/90)

Newsgroups: comp.lang.c++
Subject: Re: renaming
Summary: 
Expires: 
References: <18591@orstcs.CS.ORST.EDU> <228@taumet.COM>
Sender: 
Reply-To: roger@procase.UUCP (Roger H. Scott)
Followup-To: 
Distribution: 
Organization: proCASE Corporation, Santa Clara, CA
Keywords: 

In article <228@taumet.COM> steve@taumet.UUCP (Stephen Clamage) writes:
>In article <18591@orstcs.CS.ORST.EDU> budd@mist.CS.ORST.EDU (Tim Budd) writes:
>>	void gak(int i) { bar::geek(i); }
>>introduce[s] the run-time overhead of one additional function invocation.
>
>I know of no C++ compiler which would not inline this member function,
>and it seems unlikely that any ever would refuse to do so.  It seems
>unnecessary to introduce a new language feature, thus complicating *all*
>compilers, to make things simpler for users stuck with bad compilers.
>
>If your local C++ compiler won't inline such a simple function (meaning
>no overhead whatsoever), try to get another one.  Such a compiler is
>bound to be woefully deficient in other ways.
>-- 
>
>Steve Clamage, TauMetric Corp, steve@taumet.com

Don't you guys *build* C++ compilers?  Consider the following:

    #define redefine

    struct Base {
	...
	virtual void f();
	void implementation1_of_f();
	void implementation2_of_f();
    };

    struct Der1 : public Base {
	redefine void f() {implementation1_of_f();}
    };

    struct Der2 : public Base {
	redefine void f() {implementation2_of_f();}
    };

Are you telling me that you are going to inline Der1::f and Der2::f, both of
which are *virtual*?  Another example (with MI):

    struct AbstractThing {
	...
	virtual void f();
    };

    struct Thing1Implementation {
	void do_that_there_f_stuff();
	...
    };

    struct Thing2Implementation {
	void do_that_there_f_stuff();
	...
    };

    struct Thing1 : public AbstractThing, public Thing1Implementation {
	redefine void f() {do_that_there_f_stuff();}
    };

    struct Thing2 : public AbstractThing, public Thing2Implementation {
	redefine void f() {do_that_there_f_stuff();}
    };

Again, how are Thing1::f and Thing2::f going to be inline?

It seems like a reasonable generalization of the syntax (and semantics?) of
pure virtual functions would be to allow:

    struct Thing1 : public AbstractThing, public Thing1Implementation {
	redefine void f() = do_that_there_f_stuff;
    };

where the "initializer" of the (member) function declaration would be required
to be type compatible with the thing that it is initializing, i.e. a member
function of the same class or a public base that took the same arguments and
returned the same type.

The implementation of this is trivial - put the address of the "initializing"
function into the vtbl rather than that of a new function.

cline@cheetah.ece.clarkson.edu (Marshall Cline) (06/02/90)

In article <156@logo.procase.UUCP> roger@procase.UUCP (Roger H. Scott) writes:

> It seems like a reasonable generalization of the syntax (and semantics?) of
> pure virtual functions would be to allow:
>     struct Thing1 : public AbstractThing, public Thing1Implementation {
>	redefine void f() = do_that_there_f_stuff;
>     };

Hmmmm.  But what does this do to the conformance requirement of subtypes?
You want to change the language, the only benefit of this new language
feature being to avoid at most one virtual function call, and the cost of
the feature being that publically derived subclasses will no longer will
have the same public interface.  Hmmmm.

I know that subtype conformance isn't important to everyone, but please
don't break it for those of us who like to say `is-a'!

Marshall Cline

--
==============================================================================
Marshall Cline / Asst.Prof / ECE Dept / Clarkson Univ / Potsdam, NY 13676
cline@sun.soe.clarkson.edu / Bitnet:BH0W@CLUTX / uunet!clutx.clarkson.edu!bh0w
Voice: 315-268-3868 / FAX: 315-268-7600
Career search in progress; ECE faculty; research oriented; will send vita.
==============================================================================

roger@procase.UUCP (Roger H. Scott) (06/03/90)

In article <CLINE.90Jun2011023@cheetah.ece.clarkson.edu> cline@sun.soe.clarkson.edu (Marshall Cline) writes:
>In article <156@logo.procase.UUCP> roger@procase.UUCP (Roger H. Scott) writes:
>
>> It seems like a reasonable generalization of the syntax (and semantics?) of
>> pure virtual functions would be to allow:
>>     struct Thing1 : public AbstractThing, public Thing1Implementation {
>>	redefine void f() = do_that_there_f_stuff;
>>     };
>
>Hmmmm.  But what does this do to the conformance requirement of subtypes?
>You want to change the language, the only benefit of this new language
>feature being to avoid at most one virtual function call, and the cost of
>the feature being that publically derived subclasses will no longer will
>have the same public interface.  Hmmmm.
How do you figure?  I think you are reading something into my proposal
that is not there.  In the example above
Thing1Implementation::do_that_there_f_stuff() *is* inherited by Thing1 (not
that this fact is likely to be relevant, given that Thing1Implementation is
not by itself very useful or interesting), so:

	Thing1 *p = ...;
	p->do_that_there_f_stuff();

would be allowed, as well as

	p->f(); // which happens to do the same thing

>
>I know that subtype conformance isn't important to everyone, but please
>don't break it for those of us who like to say `is-a'!
I wouldn't dream of messing with such a thing.  I don't have any problems with
the type system, and am not out to change it either deliberately or accidentally.

By the way, you are wrong about "the only benefit ... being to avoid one virtual
function call".  There is also argument passing, which in C++ can be non-trivial
in the case of objects with X::X(const X&) defined.  For instance, imagine a
little reference-counted pointer class.  Everytime an instance of such a
class is passed to a function the object is copied and the reference count must
be bumped.  Then there's returning values ...