[comp.lang.c++] C++ enhancements

franka@mmintl.UUCP (Frank Adams) (03/20/88)

Following are some suggestions for improvements to C++.

Add a new keyword "leaf" to the language.  This is applied to a (virtual)
function declaration to indicate that the function is not redefined in any
subclass of the current class.  This enables the translator to generate a
direct call to the function for objects known to be in the current class.  I
know that the same thing can be accomplished by prefixing class-name:: to
the call, but I want the facility attached to the declaration, not the call.

As an extension, one could apply the leaf modifier to a class defintion,
which makes it illegal to define an subclasses of the class.  This in effect
makes any functions defined for the class leaf functions.

Why not let the result of applying the & operator to a reference variable be
an lvalue?  This would mean one could write something like:
	int & a = i;
	int j;
	(&a) = &j;
If the original declaration was "int & const a = i", the assignment would be
illegal.  (Note the parentheses around "&a".  Permitting them to be dropped
would require a syntax change.  This would be better, but I'm not sure off
hand how difficult it would be.)

Has anything been done yet about the ambiguity of prefix and postfix
operators when overloading "++" and "--"?  How about "operator postfix ++"
and "operator postfix --", with the unadorned forms being prefix?

It seems like it would be easy to define an alternative form for the "for"
statement:
	for { statement expression-opt ; compound-statement } statement
This permits generalized update statements as well as generalized
initialization.  (It will mean that "break" statements must, in general, be
translated into "goto"s.)

There has been some discussion recently in comp.lang.c about permitting
aggregate expressions in more general contexts.  Has this been considered
for C++?  If so, what is its status?
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

bs@alice.UUCP (03/22/88)

franka @ Ashton-Tate Corporation, East Hartford Development Center writes:

 > Following are some suggestions for improvements to C++.

I have nothing in particular against the improvements proposed here, but I
will take the opportunity to make a few general points about C++ and its
growth.

C++ is in widespread use.  Much of this use is in non-research environments;
there are more than four independent organizations producing C++ compilers
and many more building tools and libraries.

The implication is that we must be quite restrained when it comes to
``improving'' the language or else we will fracture it into several
incompatible dialects. All the compiler writers I know of have expressed
a strong support for the idea of ``one language'' and a horror of the
specter of ``feature wars'', but only restraint on all parts will make it
possible to achieve this.

This does not imply that C++ cannot change; it can, will, and does grow.
It just means that for the moment we must concentrate on getting the fabric
of the language well defined and well documented. Decorating the language
with bells and whistles to suit the very diverse tastes of advanced research
users could be severely damaging. Compatibility between C and C++ is a major
concern. Keeping the language small and clean enough to allow relatively
small and relatively clean manuals and compilers is another concern.

My contention is that even strictly upwardly compatible changes can become
a severe problem if they start appearing so fast that the compiler writers
and the users cannot keep up. For example, library writers would forever
have to agonize over which extensions they could use without antagonizing
``too many'' of their users.

Also consider this: Most of the new features would be irrelevant to YOU as
an individual user. You might find that the cost of the ability to write your
code in exactly the most elegant way according to your current taste is
the ability to run most everybody else's software.

And this: Every new feature added choses one evolutinary parth and thereby
closes all similar parths. For example, if we provided a built-in set of
features for concurrency we would be stuck with it. Even if we found a much
better solution tomorrow. This is one of my nightmares. we have many reasons
to thread very carefully.

 > Add a new keyword "leaf" to the language.  This is applied to a (virtual)
 > function declaration to indicate that the function is not redefined in any
 > subclass of the current class.  This enables the translator to generate a
 > direct call to the function for objects known to be in the current class.  I
 > know that the same thing can be accomplished by prefixing class-name:: to
 > the call, but I want the facility attached to the declaration, not the call.

I think that this is unnecessary: first because a virtual function call is
sufficiently efficient compared to a ``normal'' function call to make this
optimization far less attractive than in ``other object-oriented programming
languages,'' and second because the optimization already can be and is done in
many cases. Consider:

	class B { public: virtual f(); };
	class D : public B { public: f(); };
	class DD : public D { public: f(); };

	f(D a, D* p) {
		a.f();	// generates a non-virtual call to D::f()
			// because a is known to be a D.
			// If D::f() is an inline inlining takes place
		p->f();	// virtual call: *p might be a DD
	}

	
 > As an extension, one could apply the leaf modifier to a class definition,
 > which makes it illegal to define an subclasses of the class.  This in effect
 > makes any functions defined for the class leaf functions.

This extension would allow p->f() to be handled as a non-virtual by disallowing
the definition of DD, but is this optimization important enough to be worth
trading away the ability to derive? Is there a real need for disallowing
derivation in some cases? (if so, we would no longer be talking about an
efficiency hack, but about a feature).

 > Why not let the result of applying the & operator to a reference variable be
 > an lvalue?  This would mean one could write something like:
 > 	int & a = i;
 > 	int j;
 > 	(&a) = &j;
 > If the original declaration was "int & const a = i", the assignment would be
 > illegal.  (Note the parentheses around "&a".  Permitting them to be dropped
 > would require a syntax change.  This would be better, but I'm not sure off
 > hand how difficult it would be.)

References was carefully designed NOT to be objects. The reason for that is
that I disliked every scheme I could think of for treating a reference both
a an object in itself an as an ``invisible'' handle for the object it refers
to and that given pointers I did not see a reason for doing it. I do not find
the solutions provided by Algol68 and Simula attractive - and here I speak
from semi-painful experience. In C++, we have both pointers and references.
Clearly in an ideal world this is one concept too many and if we eliminated
pointers (which we will not do) we would have to provide ways of changing the
value of reference objects. However, given that we do have pointers I suggest
you use them where the reference semantics are too restrictive.

To get back to the example in hand, what don't I like about the scheme outlined
above? Assigning to an address (&a) looks a bit funny, but I could get over that.
Would &a++ and ++&a be allowed? &a[2] ? (Quick: where do we need parentheses?).
Is ``*&a'' always the same as ``a''? Consider:

	int* p;
	int*& r = p;
	&r = p;	// currently illegal
	p = r;
	p = *&r;	// legal? why/why not?
	*&r = p;	// legal? why/why not?
	*&r = i;	// legal? why/why not?
	p = &*r;	// legal? why/why not?	
	*r = 2;		// legal? why/why not?
	**&r = 2;	// legal? why/why not?

Actually, this proposal is probably the most sensible one I have seen for
allowing the value of a reference to change. However, the bottom line is:
What do you get by extending the language? In this case I think the answer
is
	(1) a minor notational convenience
	(2) larger manuals and compilers
	(3) the need to teach users the answers to my questions above

 > Has anything been done yet about the ambiguity of prefix and postfix
 > operators when overloading "++" and "--"?  How about "operator postfix ++"
 > and "operator postfix --", with the unadorned forms being prefix?

I am still unconvinced that this extension would add anything significant to
C++. I see that it would allow replacing pointers to some basic type with
a user-defined pointer type without any program changes (for debugging, etc.)
but I'm not convinced this is such a great idea. The distinction between ++i
and i++ is subtle and its importance is primarily to save the explicit
introduction of a temporary. Is this really the level of improvements we
want to see in C++?

 > It seems like it would be easy to define an alternative form for the "for"
 > statement:
 > 	for { statement expression-opt ; compound-statement } statement
 > This permits generalized update statements as well as generalized
 > initialization.  (It will mean that "break" statements must, in general, be
 > translated into "goto"s.)

 > There has been some discussion recently in comp.lang.c about permitting
 > aggregate expressions in more general contexts.  Has this been considered
 > for C++?  If so, what is its status?

Yes, it was considered 6 years ago. My conclusion was and is: use constructors.

lsr@Apple.COM (Larry Rosenstein) (03/23/88)

In article <2781@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes:
>Following are some suggestions for improvements to C++.
>
>Add a new keyword "leaf" to the language.  This is applied to a (virtual)
>function declaration to indicate that the function is not redefined in any
>subclass of the current class.  This enables the translator to generate a
>direct call to the function for objects known to be in the current class.  I

In MPW (Object) Pascal, the linker does this automatically by analyzing the
classes you define.

I wouldn't want to use this as an efficiency technique, because it requires
that the programmer defining the virtual member function decide whether
anyone will want to override it.  As a way of preventing people from
overriding a member function, it is a good idea.

A related idea would be to declare a virtual member function as abstract
(Smalltalk calls this subclassResponsibility).  This would be a function
that must be overridden in all subclasses, and has no implementation at the
point where it is first defined.  The purpose of such a function would be to
define behavior that all subclasses must follow (eg, all Shape objects must
Draw).


Another (unrelated) addition I would like to see is something like a delayed
method call.  My idea would be to package up an object and a virtual
function name into an Invocation object.  These objects could be passed
around and stored, and at some later time you could cause the function to be
called with the given object.  (Suppose that the function takes no
parameters.)

You could use this to attach actions to a screen button, for example.  The
same Button object could be used to do different things depending on the
Invocation object it contained.  (In Smalltalk, you can do this by creating
a block context, or by using an arbitrary Symbol as the name of a method to
execute.)

Without knowing how CFront is implemented, it seems that you could hack this
if you know how CFront assigns names.  This would be highly
implementation-dependent, however.

-- 
		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 32E  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

eric@snark.UUCP (Eric S. Raymond) (03/25/88)

In article <7757@alice.UUCP>, bs@alice.UUCP writes:
> [Replying to Frank Adams]
> > Add a new keyword "leaf" to the language...
>I think that this is unnecessary:

I don't think your agendas are incompatible. Why not add 'leaf' as a pragma?

I'll state this as a more general proposed rule for the 'what should we hack
into C++ next' game:

    OPTIMIZATION HINTS SHOULD BE PROPOSED AS OPTIONAL PRAGMAS, IF AT ALL

This way they don't clutter up the language structure. And no, scope is not
a problem. If you view the action of #pragma leaf as 'set a compiler flag that
affects processing of the next declaration' the scope is set by, of course,
the next declaration. This approach generalizes.

If X3J11 ever gets its collective head out of its collective asshole about
'noalias', they'll turn it into a collection of pragmas. As dmr has observed,
it doesn't designate an object property and doesn't belong in declarations (I
actually agree with his stronger claim that it doesn't belong in the language
at all but that's a separate issue from the one I'm addressing here).

Note: Despite the fact that I am fed up enough with the X3J11 committee to
	get extremely rude at them as above, I sincerely do *not* intend
	insult to any individual X3J11 member and do respect the good work
	the committee has done in the past. Committees are strange beasts
	with lives of their own (who wrote that line about the intelligence
	of a committee being  the lowest of its members' intelligences divided
	by the number of members?). But I *still* want to know what happened to
	the "no prior art" exclusion...]

In general I don't think optimization hints should be embedded in HLL designs
because they aren't part of the abstract semantics that HLLs are designed to
describe (cf. FORTRAN's FREQUENCY statement).

Granted there are borderline cases (Pascal's 'pure' is one that I've been
friendly to having *in the HLL itself* during moments of weakness, and a
properly-defined relative of 'noalias' might be another tempter).

But the *presumption* that things like 'leaf' deserve first-class citizenship
in a language, rather than being things you might want to tell the compiler
about how to translate some pieces of the code some of the time, is clearly
wrong. Discussion should *start* with

"Hey, howzabout '#pragma leaf'...".

and go to 'keyword leaf' only if (as Bjarne pointed out) we're talking about
a usage constraint rather than a simple performance booster.


-- 
      Eric S. Raymond                     (the mad mastermind of TMN-Netnews)
      UUCP: {{uunet,rutgers,ihnp4}!cbmvax,rutgers!vu-vlsi}!snark!eric
      Post: 22 South Warren Avenue, Malvern, PA 19355   Phone: (215)-296-5718

franka@mmintl.UUCP (Frank Adams) (03/26/88)

In article <7757@alice.UUCP> bs@alice.UUCP writes:
>franka @ Ashton-Tate Corporation, East Hartford Development Center writes:
> > Following are some suggestions for improvements to C++.
>
>C++ is in widespread use.  Much of this use is in non-research environments;
>there are more than four independent organizations producing C++ compilers
>and many more building tools and libraries.
>
>The implication is that we must be quite restrained when it comes to
>``improving'' the language or else we will fracture it into several
>incompatible dialects.

This is a good point.  On the other hand, it is never going to get any
easier to add features to the language.  Moderation is fine, but some sort
of procedure for adding relatively small increments to the language should
be in place.

> > Add a new keyword "leaf" to the language.  This is applied to a (virtual)
> > function declaration to indicate that the function is not redefined in any
> > subclass of the current class.
>
> and second because the optimization already can be and is done in
>many cases. Consider:
>
>	class B { public: virtual f(); };
>	class D : public B { public: f(); };
>
>	f(D a, D* p) {
>		a.f();	// generates a non-virtual call to D::f()

It is my impression that pointers and references to objects are
significantly more common than actual instances; thus this optimization
occurs fairly rarely in practice.  I have no hard evidence on this point.

Global optimization is another possible approach to this sort of thing; it
is clearly superior if available.
	
> Is there a real need for disallowing derivation in some cases?

A good question.  I can well imagine that a methodology might want such a
prohibition, but I don't know of any methodologies which use inheritance
which do.

There are classes in Smalltalk which one does not want to subclass, because
of implementation details.  (For example, Point has lots of methods which
build new points using "@"; if one wishes to subclass it, one will have to
replace lots of methods.  A more extreme example is SmallInteger.)  However,
nothing like this is obviously applicable to C++.


> > Why not let the result of applying the & operator to a reference variable
> > be an lvalue?
>
>Would &a++ and ++&a be allowed? &a[2] ? (Quick: where do we need
>parentheses?).

It had better be (&a)++ and (&a)[2].

>Is ``*&a'' always the same as ``a''?

Yes.

>Actually, this proposal is probably the most sensible one I have seen for
>allowing the value of a reference to change. However, the bottom line is:
>What do you get by extending the language? In this case I think the answer
>is
>	(1) a minor notational convenience

I can't really argue with this.  This was perhaps the weakest of my
suggestions.

>	(2) larger manuals and compilers

Not, I think, by very much.

> > Has anything been done yet about the ambiguity of prefix and postfix
> > operators when overloading "++" and "--"?
>
>I am still unconvinced that this extension would add anything significant to
>C++.

But here, we are talking about simplifying the manuals and user
explanations.  Why can't I do the same thing with a defined operator that I
can do with the built-in operators?
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

franka@mmintl.UUCP (Frank Adams) (03/26/88)

In article <7757@apple.Apple.Com> lsr@apple.UUCP (Larry Rosenstein) writes:
>Another (unrelated) addition I would like to see is something like a delayed
>method call.  My idea would be to package up an object and a virtual
>function name into an Invocation object.  These objects could be passed
>around and stored, and at some later time you could cause the function to be
>called with the given object.  (Suppose that the function takes no
>parameters.)

class deferred {
public:
	object *receiver;
	void (* action)(object *);

	deferred(object *thing, void (* act)(object *)) {
		receiver = thing; action = act;}
	inline void do_it() {(*action)(receiver);}
};

If the function is virtual, you may have to do something like:

	deferred button(it, &it->zoom);

but I think this works.
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

franka@mmintl.UUCP (Frank Adams) (03/29/88)

[I have cross-posted this from comp.lang.c++ to comp.lang.c, comp.lang.ada,
and comp.lang.misc, with followups directed to comp.lang.misc.  Responses
relating to one of these languages in particular should be directed to the
appropriate place.]

In article <2249424b:4311@snark.UUCP> eric@snark.UUCP (Eric S. Raymond) writes:
>I'll state this as a more general proposed rule for the 'what should we hack
>into C++ next' game:
>
>    OPTIMIZATION HINTS SHOULD BE PROPOSED AS OPTIONAL PRAGMAS, IF AT ALL

I have trouble with pragmas.  The problem is not, perhaps, intrinsic; but it
is very much in evidence in every language where I have seen them.  The
problem is that each vendor is allowed to define their own pragmas, with no
guarantee that someone else won't use the same pragma for something entirely
different.

If pragmas are going to be used, they should be as much part of the language
standard as the syntax.  A vendor may choose to follow or ignore whatever
pragmas they choose to; but *if* a pragma is not ignored, it should be used
as specified.

To expedite the introduction of new pragmas, there should be a central
repository of pragma definitions.  Compiler writers should be able to define
a new pragma, and within a few weeks have it officially recorded in the
repository.  The name may not be the one requested, but the functionality
should be.  (A review committee to go over the pragma and suggest
improvements is a tempting idea, but should not be permitted to slow down
the process.)
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108