Path: utzoo!attcan!uunet!mcsun!ukc!dcl-cs!aber-cs!athene!pcg From: pcg@cs.aber.ac.uk (Piercarlo Grandi) Newsgroups: comp.std.c++ Subject: Re: Unnecessary copying of returned object Message-ID: Date: 4 Sep 90 21:18:59 GMT References: <1990Aug31.234937.29938@athena.mit.edu> <1990Aug31.235606.166@athena.mit.edu> <11267@alice.UUCP> Sender: pcg@aber-cs.UUCP Organization: Coleg Prifysgol Cymru Lines: 100 In-reply-to: ark@alice.UUCP's message of 1 Sep 90 13:21:56 GMT On 1 Sep 90 13:21:56 GMT, ark@alice.UUCP (Andrew Koenig) said: ark> In article <1990Aug31.235606.166@athena.mit.edu>, ark> ahodgson@hstbme.mit.edu (Antony Hodgson) writes: ahodgson> Vector Vector::operator + ( Vector & A ) ahodgson> { ahodgson> Vector temp; ahodgson> // for all valid i, temp[i] = (*this)[i] + A[i] ahodgson> return temp; // copy of temp made here ahodgson> } // temp deallocated here ahodgson> Could an intelligent compiler bypass this copying without the ahodgson> help of any new syntax? ark> Yes. Yes indeed, at the expense of a substantial bloat in space and time for the compilation: ark> One fairly easy to express such an optimization would be to say ark> that `if every return statement in a function returns the same ark> local variable, and that local variable has the same type as the ark> function's return value, then the compiler should alias the local ark> variable to the return value.' This is a very good example of the divide between people like me and people who love compilers that take several hundred kilobytes of core. A compiler can discover a large number of things by careful analysis of the source; in this case, by doing two passes over each function it can discover that it can alias a local variable to the return value slot on the stack or wherever it is. Now let me observe: what is the cost of telling the compiler beforehand? virtually none. What is the cost of letting the compiler discover it? large -- you have to make two passes over each function, and delay generating real code until the second pass, while you build a full in memory representation of the procedure in the first pass, in order to check whether you can alias or not. ark> The language definition permits this optimization. But is does not permit doing without it; if you have the option of telling the compiler explicitly, like in Gnu C++, and you do, it can avoid doing any analysis, and if you do not, it could then switch to 'slow-and-big' mode (but should not IMNHO). Consider my favourite example of wise language design: the 'register' keyword is defined such that you cannot take the address of variables so tagged. Why ever, when the compiler, by the end of the function, knows whether you have taken the address of the variable or not, and can then ignore the 'register' specification if so? But simply because Classic C has been carefully designed so as to be compilable with a simple one pass compiler that has no memory between statements except for declarations (that is the reason for 'register' itself -- the compiler can allocate a register to hold a variable between statements, without ever analyzing more than one statement at a time, because you told it by a declaration that it would be worthwhile). Note that Classic C does not actually *forbid* more sophisticated compilation strategies; it makes it possible for a simple compiler to compete with a sophisticated one, thanks to some assistance from the programmer; if such assistance is not forthcoming, the compiler *can* do more work (but should not IMNHO). In C++ the trend is towards making it difficult for simple compilers to be competitive with complicated (and theref ore unreliable) ones. What is more worrying is that C++ seems to be evolving also towards requiring ever more complicated *implementation* strategies as well; consider constructors/destructors and virtuals, and more recently and ominously, virtual base classes, and in the future, templates. Consider the incredible syntax ambiguities (that could be easily removed, with virtually 100% backwards compatibility), the complexity of many rules, the fact that because of a single (IMNHO very unwise and confusing) rule a single pass compiler is actually *impossible*, and many other details. Did AT&T want to make it very difficult for anybody but themselves produce a conforming implementation? Or at least to make it so difficult to understand what a conforming implementation is so that people would stick by AT&T's for fear of the unknown? If this has been true, it has failed; it is well known that cfront is not conforming itself, i.e. AT&T have shot themselves in the foot :-). A plea: remove the damn rule that requires two pass compilation of class definitions. I think that it is damn unwise, and if people want to use a class member in a member function body that appears before its declaration, they should be damned. They should avoid doing anything so gross and unreadable. Encourage people to define member functions after the class definition, not within it! -- Piercarlo "Peter" Grandi | ARPA: pcg%uk.ac.aber.cs@nsfnet-relay.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcsun!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk