[comp.lang.c++] address of virtual function

garya@Solbourne.COM (Gary Aitken) (04/29/89)

Jonathan Shopiro's response to my earlier posting is a help in terms of
dereferencing the pointers once they have been given the proper values.
However, I don't see any solution (yet) to the problem of getting the
proper values in the pointers in the first place.

How does one get the address of the virtual function for an object, given
a pointer to the object?

	class A {
	 public:
		virtual	void f() ;
	}
	class B : public A {
	 public:
		void	f() ;
	}

	typedef void A::MEMF() ; // type for "member function of A"
	MEMF	*fp ;
	B	*bp = new B ;
	A	*objp = (A*) bp ;

	fp = &objp->f ; // if objp is REALLY a *A, I want &A::f
	                // but if it's REALLY a *B, I want &B::f
	                // again, this works in cfront, with warnings...

 /* I don't want
	fp = &A::f
	because I need the appropriate virtual function to dispatch when
	the function call is made.
 */

Or am I missing something here?  If I do
	fp = &A::f
and subsequently do a
	(bp->*fp)()
will this somehow go through the virtual table and actually call B::f if
bp is REALLY a B* object pointer?  (I can't test this right now because
our cfront is broken for these constructs right now...)
-- 
Gary Aitken

Solbourne Computer Inc.    ARPA: garya@Solbourne.COM
Longmont, CO               UUCP: ...!{boulder,sun}!stan!garya

shopiro@alice.UUCP (Jonathan Shopiro) (04/29/89)

In article <904@garya.Solbourne.COM>, garya@Solbourne.COM (Gary Aitken) writes:
> Jonathan Shopiro's response to my earlier posting is a help in terms of
> dereferencing the pointers once they have been given the proper values.
> However, I don't see any solution (yet) to the problem of getting the
> proper values in the pointers in the first place.
> 
> How does one get the address of the virtual function for an object, given
> a pointer to the object?
> 
> 	class A {
> 	 public:
> 		virtual	void f() ;
> 	}
> 	class B : public A {
> 	 public:
> 		void	f() ;
> 	}
> 
> 	typedef void A::MEMF() ; // type for "member function of A"
> 	MEMF	*fp ;
> 	B	*bp = new B ;
> 	A	*objp = (A*) bp ;
> 
> ...
> 
> Or am I missing something here?  If I do
> 	fp = &A::f
> and subsequently do a
> 	(bp->*fp)()
> will this somehow go through the virtual table and actually call B::f if
> bp is REALLY a B* object pointer?
It REALLY will.  I promise.

s
o
r
r
y

a
b
o
u
t

t
h
i
s

s
i
l
l
y

s
t
u
f
f

-- 
		Jonathan Shopiro
		AT&T Bell Laboratories, Warren, NJ  07060-0908
		research!shopiro   (201) 580-4229

ark@alice.UUCP (Andrew Koenig) (04/29/89)

In article <904@garya.Solbourne.COM>, garya@Solbourne.COM (Gary Aitken) writes:

> Or am I missing something here?  If I do
> 	fp = &A::f;
> and subsequently do a
> 	(bp->*fp)();
> will this somehow go through the virtual table and actually call B::f if
> bp is REALLY a B* object pointer?


Yes.


What you can't do is bind an object and a function pointer into
a single value.  That is, there's no type you can give x
that will let you do this sanely:

	x = &bp->f;

It would be nice, but it is extremely difficult to compile into
C because C doesn't let you get your tentacles into its
calling sequence portably.
-- 
				--Andrew Koenig
				  ark@europa.att.com

mat@mole-end.UUCP (Mark A Terribile) (04/30/89)

> How does one get the address of the virtual function for an object, given
> a pointer to the object?
 
> 	B	*bp = new B ;
> 	A	*objp = (A*) bp ;
 
> 	fp = &objp->f ; // if objp is REALLY a *A, I want &A::f
> 	                // but if it's REALLY a *B, I want &B::f
 
>  I don't want   fp = &A::f  because I need the appropriate virtual function
>  to dispatch when the function call is made. ...  Or am I missing something
>  here?  If I do     fp = &A::f     and subsequently do a    (bp->*fp)()
>  will this somehow go through the virtual table and actually call   B::f   if
>  bp is REALLY a B* object pointer?  ...

It sure will.  Pointers to virtual members are themselves virtual and go
through the virtual tables.  How, you ask, is it done?  Take my word, you
don't want to know.  It's ugly.  Worse, it imposes a couple of extra
instructions of cost on every call-through-a-pointer-to-member-function if
the class has *any* virtual members (or perhaps its any virtual members whose
argument signatures match; I don't know for sure.)  The cost really isn't
that great.

One of the versions of cfront has a bug that causes it to generate code
which triggers error messages or warnings from the C compiler.  I don't
recall which version it is--it's been a long time since I had to deal with
the problem.  I had to work around it by creating a friend class whose
member functions' only job was to call the appropriate virtual functions
in the class hierarchy of interest.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

jima@hplsla.HP.COM (Jim Adcock) (05/06/89)

> It sure will.  Pointers to virtual members are themselves virtual and go
> through the virtual tables.  How, you ask, is it done?  Take my word, you
> don't want to know.  It's ugly.  Worse, it imposes a couple of extra
> instructions of cost on every call-through-a-pointer-to-member-function if
> the class has *any* virtual members (or perhaps its any virtual members whose
> argument signatures match; I don't know for sure.)  The cost really isn't
> that great.

Well, I find the cost somewhat discouraging if all one is trying to do is
return a value from an object of uncertain class.  For example, try to
find an inexpensive way to get a hierarchy of classes to return information
about their sizes -- presumably:

class baseclass
{
    virtual int size(){return sizeof(baseclass);}
};

class derivedclass : baseclass
{
    int size(){return sizeof(derivedclass);}
}


For these simple get-a-value, put-a-value type virtual access functions
one could hope for code that compiles to a simple double indirection:

baseclassptr->size();

compiles to:

baseclassptr->(vtable+offset_of_size)->a_constant_equal_to_size;

or maybe even:

baseclassptr->vtable[offset_of_size_constant]

The present approach gives code that is about 10X slower than one
would hope for in these simple, everyday cases.

Again, for OOP to be affordable, these simple, everyday "get" and
"put" type functionalities must be handled at minimal cost.
Otherwise programmers will violate strict encapsulation, and come
up with "hack" solutions.

jss@hector.UUCP (Jerry Schwarz) (05/08/89)

In article <6590114@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>
>Again, for OOP to be affordable, these simple, everyday "get" and
>"put" type functionalities must be handled at minimal cost.
>Otherwise programmers will violate strict encapsulation, and come
>up with "hack" solutions.

I get a frustrated by assertions of this kind.  By any standard C++
is "affordable", especially when compared to languages like Smalltalk
or Objective C.  Note that the item I am replying to was sumbmitted
only to  comp.lang.c++ so I have to read this as a suggestion that
C++ isn't "affortdable".  (I suppose I could also read this as an
argument for my contention that C++ supports non object
oriented styles and therefore derives its affordability by avoiding
OOP when neccessary, but the tenor of the item I'm replying to
doesn't suggest that reading to me.  I apologize if I'm misreading
Jim Adcocks note.)

In fact, C++ puts you at a low enough level so that (with out
violating the type discipline) it is possible to program the
operation under discussion (finding the "actual" size of an
object) as a simple lookup.

class B  
public
	const size_t	size ;
	B(int i) : Size(i) ;
}  ;

class D : B {
	D(...) : B(sizeof(D)) { ... } 
} ;

	B* p ; ...  p->size ... ; 

Yes, there is a certain amount of pain involved in programming this
explicitly.  But recall that the original complaint was that C++
doesn't provided an "affordable" enough way to do this operation.


Jerry Schwarz
AT&T Bell Labs, Murray Hill

mat@mole-end.UUCP (Mark A Terribile) (05/09/89)

In article <6590114@hplsla.HP.COM>, jima@hplsla.HP.COM (Jim Adcock) writes:
> > It sure will.  Pointers to virtual members are themselves virtual and go
> > through the virtual tables.  ...  it imposes a couple of extra instructions
> > of cost on every call-through-a-pointer-to-member-function if the class
> > has *any* virtual members ...  The cost really isn't that great.
 
> Well, I find the cost somewhat discouraging ...
 
> class baseclass
> {
>     virtual int size(){return sizeof(baseclass);}
> };

>  . . .

> baseclassptr->size();

Not relevant.  This is pointer-to-object, NOT pointer-to-member.  Pointer-to
member isn't that common an operation:

	int (baseclass::*fn)() = &baseclass::size;

	i = (baseclass_obj.*fn)();
	j = (baseclass_ptr->*fn)();
 

> For these simple get-a-value, put-a-value type virtual access functions
> one could hope for code that compiles to a simple double indirection:
> 
> baseclassptr->size();

> compiles to:

> baseclassptr->(vtable+offset_of_size)->a_constant_equal_to_size;

> or maybe even:
 
> baseclassptr->vtable[offset_of_size_constant]
 
> The present approach gives code that is about 10X slower than one
> would hope for in these simple, everyday cases.

True, this could be better implemented ASSUMING you know that all functions
derived from this virtual member will be used in this way.

All in all, the 10X cost is a matter of half-a-dozen extra instructions.
Unless you can show that this is more than 2% of the cost of your program, I
advise you not to worry about it.
 
> Again, for OOP to be affordable, these simple, everyday "get" and
> "put" type functionalities must be handled at minimal cost.
> Otherwise programmers will violate strict encapsulation, and come
> up with "hack" solutions.

C++ is still at least an order of magnitude faster of Objective-C, and
encourages this sort of interface.  Objective-C doesn't seem to.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

jima@hplsla.HP.COM (Jim Adcock) (05/10/89)

> >Again, for OOP to be affordable, these simple, everyday "get" and
> >"put" type functionalities must be handled at minimal cost.
> >Otherwise programmers will violate strict encapsulation, and come
> >up with "hack" solutions.
> 
> I get a frustrated by assertions of this kind.  By any standard C++
> is "affordable", especially when compared to languages like Smalltalk
> or Objective C.  Note that the item I am replying to was sumbmitted
> only to  comp.lang.c++ so I have to read this as a suggestion that
> C++ isn't "affortdable".  (I suppose I could also read this as an
> argument for my contention that C++ supports non object
> oriented styles and therefore derives its affordability by avoiding
> OOP when neccessary, but the tenor of the item I'm replying to
> doesn't suggest that reading to me.  I apologize if I'm misreading
> Jim Adcocks note.)

Sorry, I meant my comments in the context of the relative cost of
virtual functions, compared to simple lookups as you discuss below:
 
> In fact, C++ puts you at a low enough level so that (with out
> violating the type discipline) it is possible to program the
> operation under discussion (finding the "actual" size of an
> object) as a simple lookup.
> 
> class B  
> public
> 	const size_t	size ;
> 	B(int i) : Size(i) ;
> }  ;
> 
> class D : B {
> 	D(...) : B(sizeof(D)) { ... } 
> } ;
> 
> 	B* p ; ...  p->size ... ; 
> 
> Yes, there is a certain amount of pain involved in programming this
> explicitly.  But recall that the original complaint was that C++
> doesn't provided an "affordable" enough way to do this operation.

Again, the complaint is that virtual functions [as presently implemented
in cfront with a pretty good backend C compiler] is too expensive
relative to these simple lookups.  While there are good optimizing C
compilers out there, what they are good at optimizing is not the
kind of code cfront produces.  If you had a backend C compiler that
can infer when to inline functions, or look at constant tables
(as in vtables) and not add constants of zero, etc, etc, then
you presumably could get some pretty good code when using cfront.
Alternately, presumably, some of the kinds of optimizations specific
to C++ could be put into cfront, and more general optimizations
could be left to back end compilers.  Unfortunately, at least when
using K&R compilers for the back end, cfront knows a lot more about
the code to be produced than the backend compiler.  So cfront would
be the place that a lot of the optimzations would have to occur.

So, for example, right now, with my combination of cfront and
back end compiler, Jerry's approach, where you violate the encapsulation
of an object, access its instance variables directly, and lock
future derived classes into using one approach to returning
"size", and force a syntax of p->size rather than p->size() --
then generates code like such:

	movel	a2@,sp@-

Where as if one takes the "Object Oriented" approach of using
virtual functions to return these values, so that some future
class -- a linked list maybe -- can have a virtual function
that calculates "p->size()" on the fly, then the [minimum]
code that gets generated is:

	movel	a3@(4),a0
	addqw	#8,a0
	addw	a0@,a3
	movel	a3,sp@-
	movel	a0@(4),a0
	jbsr	a0@
	 |
	 |
	 V
	link	a6,#0
	movel	a6@(8),a0
	movel	a0@,d0
	unlk	a6
	rts
	 |
	 |
	 V
	movel	d0,sp@-

So, as I was trying to say before, one can clearly see that 
attempts to encapsulate an object, accessing its instance
variables using virtual functions, in order to allow flexibility
in future derived classes, presently costs dearly; rather than
just punting, and allowing direct access to some of an objects
instance variables.  About 10-20X slower.

In many [most?] cases, a good optimizing C++ -> assembly compiler,
or a good combination of a good optimizing C++ -> C and C -> asm
compiler would be able to avoid generating most of this code most
of the time.  I don't see this is a problem with the language.
Its just that C++ compilers need to do a better job of optimizing
either the C or assembly code they produce.  Its silly to pretend
an optimizing C compiler is going to find all the optimizations
possible out of the stuff cfront presently produces!

While there are times when Jerry's suggestion is the way to go,
there are also times when one would like to preserve the flexibility
that virtual functions allow, and one would still be able to count
on code being produced at minimum cost.  The present 10-20X factor 
is simply too much.

BUT: C++ is still much cheaper than Smalltalk and ObjC, even with the
present weaknesses in the code produced.

jss@hector.UUCP (Jerry Schwarz) (05/10/89)

In article <6590118@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:

   class B {
   public
   	const size_t	size ;
   	B(int i) : size(i) { }  ;
   }  ;
   
   class D : B {
   	D(...) : B(sizeof(D)) { ... } 
   } ;
   
   	B* p ; ...  p->size ... ; 

>Again, the complaint is that virtual functions [as presently implemented
>in cfront with a pretty good backend C compiler] is too expensive
>relative to these simple lookups.  

And my point is that C++ puts into the programmers hands the tools
needed to generate whatever balance of lookup versus function calls
is desired.

>
>So, for example, right now, with my combination of cfront and
>back end compiler, Jerry's approach, where you violate the encapsulation
>of an object, access its instance variables directly, and lock
>future derived classes into using one approach to returning
>"size", 

The design of classes that you intend to use as base classes is
definitely non-trivial.  The decision to "lock in" the derived
classes in order to generate direct lookups for size, is a design
decision that should be weighed carefully.  I was illustrating how to
implement it once it had been made. I'd like to emphasize this point,
because I find it frequently overlooked.

**********************************
 The design of the "protected interface", which is what I call the
 interface between the base class and derived classes,  requires
 careful consideration.  One of C++ strengths is that it provides
 flexibility in specifying this interface. Consequently there is an
 obligation on the C++ programmer to use the flexibility wisely.
**********************************

>and force a syntax of p->size rather than p->size() --

That was simply an omission to save a couple of lines in the example
that I thought were irrelevant to the issues being discussed. What I
would consider good style is something like

	class B {
	public:	size_t	size() { return x_size ; }
	protected:
		B(int i) : x_size(i) {  } 
	private: 
		size_t	x_size { }
	} ;

Using C++ I can cause code to be generated as a direct lookup or as
an indirect function call.  Perhaps I've overlooked something. If Jim
suggests an alternative kind of code I'll try to figure out a way to
get it generated.  I don't see how any amount of optimization in a
compiler can do anything better unless the indirect function call is
speeded up. A machine in which a virtual function call takes 20X a
load is not a machine designed to run C++ code efficiently.
Personally, I think his complaint is with the hardware designers.
Maybe this discussion should be redirected to comp.arch :-)

Jerry Schwarz
AT&T Bell Labs, Murray Hill

jima@hplsla.HP.COM (Jim Adcock) (05/11/89)

>  The design of the "protected interface", which is what I call the
>  interface between the base class and derived classes,  requires
>  careful consideration.  One of C++ strengths is that it provides
>  flexibility in specifying this interface. Consequently there is an
>  obligation on the C++ programmer to use the flexibility wisely.

I would claim this obligation falls not simply on the programmer,
but also on the C++ compiler designer, and on the person [say C
ompiler desginer] who turns the intermediate representation into
machine code.  The C++ programmer should be free to specify 
flexibility where needed, and the C++ and C compilers should be
smart enough not to use that flexibility where not need.  Marking
a function "virtual" should not be a unilateral declaration for
C and/or C++ compilers to generate bad code.

> Using C++ I can cause code to be generated as a direct lookup or as
> an indirect function call.  Perhaps I've overlooked something. If Jim
> suggests an alternative kind of code I'll try to figure out a way to
> get it generated.  I don't see how any amount of optimization in a
> compiler can do anything better unless the indirect function call is
> speeded up. A machine in which a virtual function call takes 20X a
> load is not a machine designed to run C++ code efficiently.
> Personally, I think his complaint is with the hardware designers.
> Maybe this discussion should be redirected to comp.arch :-)

Hell, if hardware designers were forced to design new machines --
-- and customers were forced to buy them -- everytime someone dreamed up
a new language -- then even ObjC could run quickly!

I have no problem with C++ *the language*, it *can* be efficiently
implemented on today's machine -- I just haven't yet seen a C++
compiler that *does* implement major details of the language efficiently.
The biggest disappointment so far is unnecessary expansion of
inline virtual functions into table lookup + indirect function calls.

Again, if one declares a "virtual function" for size inline; if
that inline function just returns a value; and if which virtual
function needs actually be called can be uniquely determined at
compile time -- then one could hope the assembly that gets generated
would be:

	movel	a2@,sp@-

Whereas, what *I* *always* get, no matter *how* I call a virtual
function [from *my* combination of C++/C compilers] is:

	movel	a3@(4),a0
	addqw	#8,a0
	addw	a0@,a3
	movel	a3,sp@-
	movel	a0@(4),a0
	jbsr	a0@
	 |
	 |
	 V
	link	a6,#0
	movel	a6@(8),a0
	movel	a0@,d0
	unlk	a6
	rts
	 |
	 |
	 V
	movel	d0,sp@-

which is 11 assembly instructions rather than one.  I am not about
to bother trying to count clock cycles associated with these
sequences, but my guess is with the greater complexity of the
instructions in the second sequence, the higher chance of cache
misses, etc, the second sequence is actually about 20X the first
[single instruction] sequence.

Looking at the second sequence, one sees that really the assembly
code generator ought to be smart enough to leave out the link/unlk
sequence, and return the value stack relative [unfortunately, most
code generators I've seen are reluctant to do this]:

	movel	a3@(4),a0
	addqw	#8,a0
	addw	a0@,a3
	movel	a3,sp@-
	movel	a0@(4),a0
	jbsr	a0@
	 |
	 |
	 V
	movel	sp@(8),a0
	movel	a0@,d0
	rts
	 |
	 |
	 V
	movel	d0,sp@-

This would save about 20% of the cost.

Next, the C++ compiler should be smart enough to recognize the
frequent situation where multiple inheritence is not being used:

        movel  a3@(4),a0
	jbsr	a0@
	 |
	 |
	 V
	movel	sp@(8),a0
	movel	a0@,d0
	rts
	 |
	 |
	 V
	movel	d0,sp@-

This would save about another 20-30% of the cost.

Finally, simply declaring a function "virtual" should not "poison"
the function, forcing the full table lookup indirect function call
sequence returning a single value, when from context the C++
compiler can determine which [inline] virtual function actually
needs to be called.  So frequently, the code sequence could be 
reduced to:

	movel	a2@,sp@-

In summary, common optimizing "code generators" [C compilers] are
not well suited to the unique needs of generating C++ code, and
C++ compilers are not giving the code generators particularly
good C code to begin with.

To really "support" object oriented programming in C++, virtual
functions need to be implemented more efficiently.  Programmers
should not be unnecessarily forced to make functions non-virtual
simply because of the inefficiencies of existing C++ front ends
or C back ends. Both need to be better.

jss@hector.UUCP (Jerry Schwarz) (05/11/89)

In article <6590119@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>
>I have no problem with C++ *the language*, it *can* be efficiently
>implemented on today's machine -- I just haven't yet seen a C++
>compiler that *does* implement major details of the language efficiently.

This was not at all clear from your earlier remarks (at least not to
me.)  My earlier notes were addressing language design issues, not
optimization issues.  Complaints about the quality of optimizations
of compilers ought to specify what compiler you're complaining about.

>
>The biggest disappointment so far is unnecessary expansion of
>inline virtual functions into table lookup + indirect function calls.
>

You may be happy to learn that the pre-release 2.0 does expand
virtual functions inline when it can determine the correct version.

	struct K { 	
		virtual int size() { return sizeof(K) ; } ;
	} ;

	void g() {
		K k ;
		int s = k.f() ; 
			// this is expanded into a simple
			// assignment in sizeof(struct K)
	}

Jerry Schwarz
AT&T Bell Labs, Murray Hill

jjc@jclark.UUCP (James Clark) (05/11/89)

In article <6590114@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:

   Well, I find the cost somewhat discouraging if all one is trying to do is
   return a value from an object of uncertain class.  For example, try to
   find an inexpensive way to get a hierarchy of classes to return information
   about their sizes -- presumably:

   class baseclass
   {
       virtual int size(){return sizeof(baseclass);}
   };

   class derivedclass : baseclass
   {
       int size(){return sizeof(derivedclass);}
   }


   For these simple get-a-value, put-a-value type virtual access functions
   one could hope for code that compiles to a simple double indirection:

   baseclassptr->size();

   compiles to:

   baseclassptr->(vtable+offset_of_size)->a_constant_equal_to_size;

   or maybe even:

   baseclassptr->vtable[offset_of_size_constant]


One way to handle this might be to extend the language to support
virtual static const data members: virtual in that accesses to them go
through the vtable, static in that they are per class rather than per
instance. Then one could say:

struct baseclass {
  virtual static const int size = sizeof(baseclass);
};

struct derivedclass : baseclass {
  static const int size = sizeof(derivedclass);
};

One would be able to access such a member like any normal data member
of the class.

James Clark
jjc@jclark.uucp

mat@mole-end.UUCP (Mark A Terribile) (05/11/89)

> > >Again, for OOP to be affordable, these simple, everyday "get" and
> > >"put" type functionalities must be handled at minimal cost.

> > I get a frustrated by assertions of this kind.  By any standard C++
> > is "affordable", ...

> Sorry, I meant my comments in the context of the relative cost of
> virtual functions, compared to simple lookups as you discuss below:
  
	[Virtual function calls when all that's needed is a stored
	 value representing ``sizeof'']
 
> ...  Unfortunately, at least when using K&R compilers for the back end,
> cfront knows a lot more about the code to be produced than the backend
> compiler.  So cfront would be the place that a lot of the optimzations
> would have to occur.


I think that this is wrong.  Remember that anywhere the class is visible,
a programmer may derive a new class with a replacement function that can't
be implemented as a constant lookup.

The only way to avoid this is to make the original base class promise
that this won't be done, and then to enforce the promise.  This means a
*declaration* to that effect.

What you really want, I think, is a virtual const.  I think it's a neat
idea and useful for certain purposes, *but* it's a new language feature
and implementing every feature that might be composed at the fringe of the
language smacks of PL/I.  Have we forgotten wher *that* leads?

Allowing the constructor to initialize a const member with the sizeof is, all
in all, a reasonable idea, except that it only works for the base that owns
that member.  It has to be written as an assignment, I believe.  (Still not
too bad, though not quite as safe in the face of program changes.)
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

mat@mole-end.UUCP (Mark A Terribile) (05/11/89)

	[The debate about how to store and access the size of an
	 object in an inheritance tree ... or anything else that
	 is constant per base or derived type ...]

>    So, for example, right now, with my combination of cfront and back end
>    compiler, Jerry's approach, where you violate the encapsulation of an
>    object, access its instance variables directly, and lock future
>    derived classes into using one approach to returning "size", and force
>    a syntax of p->size rather than p->size() --

First, I think that Jerry's article about the protected interface and its
intended customers answers this.  It is often reasonable to make a design
decision, in a particular circumstance, that constrains you later in some
way.

OOP people would like to have total code reusability.  The problem with this
approach is that the underlying algorithms have widely varying time and
space properties and one solution is *rarely* correct for everything.  See
grep(1) on a version of ``The UNIX (tm, etc.) Time Sharing System.''  See
the debate now raging on comp.lang.c about free store management.  Sometimes
you have to pay a price in generality to get performance.  C++ allows you to
make these decisions; it does not force the answers on you.

> For crying out loud!  If you are so concerned about performance that
> you would be willing to rape your code if it saved you a few cycles,
> how about this radical approach: write in the object oriented style,
> AND GET A REAL MACHINE.  ...

The job of the engineer is to move those cost/performance/reliability curves
that he can to the best advantage.  That doesn't mean that he can change
his environment.  If there is a glut of cheap 8088s around, he can build a
cheaper product, sell more, and thereby pay for more effort to improve the
performance and reliability.  He can also return more money to the
stockholders, who will respond by asking him to do something else that they
find useful (i.e. profitable to them and *presumably* to the people who buy
the product because they find it useful).

The discussions here show that C++, by not imposing its own ``compleat''
definition of OOP, is engendering all sorts of interesting debate about
how OOP can be used to real effect in the real world.  THIS IS GOOD.  On
the other hand, using the word ``rape'' to describe consensual union
between those who (presumably) have the right to that union is distortion
and pointless inflammation of passions.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile

jima@hplsla.HP.COM (Jim Adcock) (05/12/89)

> In article <6590119@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
> >
> >I have no problem with C++ *the language*, it *can* be efficiently
> >implemented on today's machine -- I just haven't yet seen a C++
> >compiler that *does* implement major details of the language efficiently.
> 
> This was not at all clear from your earlier remarks (at least not to
> me.)  My earlier notes were addressing language design issues, not
> optimization issues.  

I'm a language user, not a designer.  Either give me the constructs I need
to use the language efficiently, or make compilers smart enough to 
optimize out excess generality where it's not needed.  Allowing access
to members [at least statics] through the vtable would be one step in
the right direction.  Or having a compiler smart enough to inline
virtual functions where one could reasonably expect to see inlined
virtual functions would be another step in the right direction.

Personally, I believe that it is better if most of these smarts are
in the compiler.  Compilers that figure out what to register, for 
example, rather than having to specify what a user wants to "register",
is an old example from the "C" world.

> Complaints about the quality of optimizations
> of compilers ought to specify what compiler you're complaining about.

I agree Jerry.  And as I've complained to you before, I ought to be able
to discuss these things freely [like what compiler I'm using]
-- especially since people at AT&T are discussing these things freely.  
But agreements between AT&T and HP prevent me from discussing these 
things freely -- I've gotten my hands slapped before.  
And then *you* complain about my inability
to discuss these things freely.  I think that is unfair.  If AT&T
people are free to discuss these things, then so should I be.  How
about calling off your lawyers, so that we can discuss these things
publicly?

> >The biggest disappointment so far is unnecessary expansion of
> >inline virtual functions into table lookup + indirect function calls.
> 
> You may be happy to learn that the pre-release 2.0 does expand
> virtual functions inline when it can determine the correct version.
> 
> 	struct K { 	
> 		virtual int size() { return sizeof(K) ; } ;
> 	} ;
> 
> 	void g() {
> 		K k ;
> 		int s = k.f() ; 
> 			// this is expanded into a simple
> 			// assignment in sizeof(struct K)
> 	}
> 

Okay, so perhaps you can tell us whether the release version of 2.0
will be able to inline in the following almost-as-trivial situation:

class K 
{     
public:
    virtual int size() { return sizeof(K) ; } ;
} ;

class L 
{     
int stuff;
public:
    virtual int size() { return sizeof(L) ; } ;
} ;

void g() {
    K k;
    L l;
    int s = k.size() ; 
        // is this example expanded into a simple
        // assignment in sizeof(struct K) ???
	// Why, or Why Not ???
}

Please test this example before you answer.

When 2.0 does comes out, how are people going to know what it can,
or can't do?  Are some of these important issues going to be
openly addressed?  Can we get a list of what new features are,
or are not going to be in 2.0?  Can we get a list of limitations
on 2.0 -- where or where not will it be smart enough to inline,
for example?

Or are customers expected to buy a pig in a poke?

jima@hplsla.HP.COM (Jim Adcock) (05/12/89)

And while I'm asking for some C++ optimizations, is it possible
that we will ever see a compiler that doesn't make gratuitous
use of the & operator in the C code it generates?

Code fragments like:

(& __1glop) -> __gloop

instead of:

 __1glop . __gloop

And:

(( __1thisglop = __1thatglop ) , & __1thisglop ) ;

Instead of:

( __1thisglop = __1thatglop ) ;

guarantees (in the optimizing C compilers that I know of) that
the structures whose address is taken actually exists and resides
in memory.  Whereas, without the & operator, the structures
[if small] may reside in registers, and maybe only those fields
of the "structure" that are actually used.  Also & __1glop, where
neither & __1glop nor __1glop ever actually get used, still causes
space on the stack for __1glop to be allocated.

While one might claim that optimizing C compilers shouldn't interpret
&something to mean that something has to be -- and be in memory,
this has been the traditional interpretation of & in C.

Seems like C++ should be able to be smart enough to avoid gratuitous
& operators, and comma expressions whose return values are clearly not 
used.

jss@hector.UUCP (Jerry Schwarz) (05/12/89)

In article <6590121@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:

>
>Okay, so perhaps you can tell us whether the release version of 2.0
>will be able to inline in the following almost-as-trivial situation:
...

I was going to ignore that question, because I cannot make any
commitments about the released 2.0.

However,  for the record, I ran that code and  the current cfront
installed on my machine inlines the call of k.size().

I personally doubt that this optimization is important.  In practice
I believe very few calls to virtual functions are even theoretically
inlinable.

Jerry Schwarz
AT&T Bell Labs, Murray Hill

rfg@riunite.ACA.MCC.COM (Ron Guilmette) (05/14/89)

In article <6590121@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>
>I agree Jerry.  And as I've complained to you before, I ought to be able
>to discuss these things freely [like what compiler I'm using]
>-- especially since people at AT&T are discussing these things freely.  
>But agreements between AT&T and HP prevent me from discussing these 
>things freely -- I've gotten my hands slapped before.  
>And then *you* complain about my inability
>to discuss these things freely.  I think that is unfair.  If AT&T
>people are free to discuss these things, then so should I be.  How
>about calling off your lawyers, so that we can discuss these things
>publicly?

Jim,

If you are really getting hassled for simply trying to get some facts
about cfront 2.0 out in the broad daylight, then that is obviously a
travesty.  I am reminded of the DoD's tendency to cloak even the most
innocent research in secrecy.  I believe that many uproars have been
caused by the DoD barring foreigners from various conferences, etc.
The uproar comes when people realize that a free flow of information
is one of the fundamental ingredients of progress.  I believe that
that applies to C++ as well.

>When 2.0 does comes out, how are people going to know what it can,
>or can't do?

Try it!  Then post your results here.  I'm sure that a lot of us
(me especially) would like to see some good test cases posted
here which show either things that do work or things that don't.

>Are some of these important issues going to be
>openly addressed?

I believe that that is what this newsgroup is for.

>Can we get a list of what new features are,
>or are not going to be in 2.0?

Correct me if I'm wrong, but I believe that it has been stated here
(several times) already that a description of 2.0 features will be
posted here at about the time of the release.

>Can we get a list of limitations
>on 2.0 ...

Does HP publish such lists for its own software products?  I think
not.  Let he who is without sin cast the first stone.  In general,
I expect hell to freeze over before total honesty with customers
becomes the norm in the software end of the business.

>Or are customers expected to buy a pig in a poke?

No. If you think that you are being mislead I suggest that you *not*
buy the product.
-- 
// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

jss@hector.UUCP (Jerry Schwarz) (05/14/89)

In article <205@riunite.ACA.MCC.COM> rfg@riunite.UUCP (Ron Guilmette) writes:
>
>If you are really getting hassled for simply trying to get some facts
>about cfront 2.0 out in the broad daylight, then that is obviously a
>travesty.  

This is exactly the problem.  There are no "facts about 2.0" because
2.0 does not yet exist.  This is not facetious, many of the questions
people have about detailed coding issues have only recently been
settled.

It is also not completely hypothetical.  Its pretty clear (from the
earlier items in this discussion)  Ron has wanted to say "2.0 never
inlines calls to virtual members, even when it should know which
version is required".

But since the current version on my system does do such inlining
it seems likely that this will not be true of 2.0.  

Jerry Schwarz
AT&T Bell Labs, Murray Hill

jima@hplsla.HP.COM (Jim Adcock) (05/15/89)

> If you are really getting hassled for simply trying to get some facts
> about cfront 2.0 out in the broad daylight, then that is obviously a
> travesty.  I am reminded of the DoD's tendency to cloak even the most
> innocent research in secrecy.  I believe that many uproars have been
> caused by the DoD barring foreigners from various conferences, etc.
> The uproar comes when people realize that a free flow of information
> is one of the fundamental ingredients of progress.  I believe that
> that applies to C++ as well.

Well, again, my frustration is that AT&T people are able to comment
openly on 2.0, and I'm not.  I can appreciate that company's have
many legitimate and illigitamate reasons to keep new product
releases quiet, but to have AT&T people be able to comment, and not
I, I find frustrating.  Either the cat in the bag, or out of the bag --
but halfway is too wierd.  Not to imply 2.0 was ever *in* the bag.

Regards "free flow of information," I feel once 2.0 is discussed on notes,
then I should be free to discuss it too.  But I haven't gotten permission
to do so.  And so since I don't like being stomped on, I feel this
continuing frustration of not being to speak freely.

I continue to believe that the main source of this problem is a
failure to cleanly differentiate between C++ *the language* and
C++ *vendor XYZ's product*.
 
> >When 2.0 does comes out, how are people going to know what it can,
> >or can't do?
> 
> Try it!  Then post your results here.  I'm sure that a lot of us
> (me especially) would like to see some good test cases posted
> here which show either things that do work or things that don't.

I'm getting sick and tired trying to reverse engineer C++ compilers --
including g++.  [By reverse engineer I mean trying to understand
what kind of code its going to produce in various situations.]
Does the language include such-a-such?  Write code
to try it.  Then unscamble the so-called "C" code that the AT&T
compiler produces.  Or stare at the assembly g++ produces.  Did
you make a mistake in your coding?  Does the compiler have a bug?
Is this an unimplemented feature?  Did you misunderstand that feature
of the language?  Can you mentally uncipher the name encodings used?
Is this a "feature" of the language or the compiler you're fighting with.
Etc, etc, etc.

Wouldn't it be easier if compiler writers just wrote a 20 page user's guide
that states how their compilers handles various major issues in C++?
In-line functions? Virtual functions? Name encoding?  Operator overloading?
etc?  Multiple inheritence? Parameterized classes? .....Rather than forcing 
each user to try to reverse engineer these things on each compiler on each 
new release? 
 
> Does HP publish such lists for its own software products?  I think
> not.  Let he who is without sin cast the first stone.  In general,
> I expect hell to freeze over before total honesty with customers
> becomes the norm in the software end of the business.

There certainly are some such lists for some such software products.
If anyone needs any information on HP products, I, among many others,
will do their best to get it for you.  My phone number is (206)-335-2138.

But, I cannot pretend to represent HP.  I am one person in 100,000.
Gnu people seem to confuse individuals with the companies they work
for.  Which is strange -- at least unless those individuals confuse 
themselves with the company they work for.  The above is not to imply
I'm satisfied with the way HP does business.  I'm not.  For example,
I'd like HP to support C++ directly....

If we waited for people without sin to throw the first stone, there
would be no notes discussions.  Total honesty is like the skins of an 
onion.  I do not see software as more dishonest than other businesses.
Like real estate :-)

> >Or are customers expected to buy a pig in a poke?
> 
> No. If you think that you are being mislead I suggest that you *not*
> buy the product.

I look forward to the day when I can get "complete" C++ compilers from
a dozen vendors.  Presently my two choices are from AT&T and Gnu.
Which sometimes feels like getting stuck between a rock and a hard 
place.  No matter whose compiler I use I am forced to "buy" into
learning it, and "reverse engineering it."  Which is the true cost.

I trust C++ *the language* and feel it is headed in the right direction.

I feel frustrated by C++ *the vendor XYZ's product* [incl Gnu], which are
not well enough supported for my tastes.  Recent software reviews seem
to echo these frustrations.

jima@hplsla.HP.COM (Jim Adcock) (05/18/89)

> The folks from AT&T have stated, in this newsgroup, on several
> occasions, that they are working on a complete reference manual for
> C++, intended to provide a full specification of the language.  They
> already know that such a thing is urgently needed; it won't do any
> good to keep reminding them.  I'm as eager to receive a final and
> complete spec as everyone else, but I understand that these things are
> quite a lot of work, and they take time.

I'm not talking about a complete up-to-date language reference -- although
g*d knows we need such a thing.  I'm talking about a reference on how
a *compiler* "works" -- what kind of code it generates, and why, in
a variety of situations?  And what are its limitations, where does it
fail to generate code?  The areas I listed before are what confuses me
the most about existing compilers -- also how they handle automatic
generation of functions to handle assignment, initialization, how temporaries
are handled etc.

I can make little changes in C++ code, and get radically differing results
in the code generated -- for no apparent reasons.  There are many situations
where I have not been able to "reverse engineer" what is going on.  It
would be nice to know.

The code generation issues are much more complex in C++ than in C.
It's important to know how a compiler is going to handle various situations,
and how the various compilers differ.

dlw@odi.com (Dan Weinreb) (05/18/89)

In article <6590126@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:

   Wouldn't it be easier if compiler writers just wrote a 20 page user's guide
   that states how their compilers handles various major issues in C++?
   In-line functions? Virtual functions? Name encoding?  Operator overloading?
   etc?  Multiple inheritence? Parameterized classes? .....Rather than forcing 
   each user to try to reverse engineer these things on each compiler on each 
   new release? 

The folks from AT&T have stated, in this newsgroup, on several
occasions, that they are working on a complete reference manual for
C++, intended to provide a full specification of the language.  They
already know that such a thing is urgently needed; it won't do any
good to keep reminding them.  I'm as eager to receive a final and
complete spec as everyone else, but I understand that these things are
quite a lot of work, and they take time.

   I trust C++ *the language* and feel it is headed in the right direction.

   I feel frustrated by C++ *the vendor XYZ's product* [incl Gnu], which are
   not well enough supported for my tastes.  Recent software reviews seem
   to echo these frustrations.

Yes, the state of things right at the moment is not very good for the
present users; things are still young, and the users are still
pioneers to some extent.  I think most of us are using C++ because we
are reasonably confident that the vendors intend to put in the effort
to stabilize the language definition, and produce compilers and other
tools that will be mature and well-debugged.

The user community should try to provide criticism and feedback that
is productive and useful to the implementors, such as specific bug
reports, feedback about what language features seem to be particularly
confusing or troublesome, indications of what needs users have that
are not being fulfilled by the present language/compiler, etc.  That's
the best way we can encourage them, and help them produce the
high-quality product that we're all looking forward to.

Dan Weinreb     Object Design, Inc.     dlw@odi.com