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