dpw@tcom.stc.co.uk (David Weeks) (02/07/90)
This is a request for information on C++ coding "guidelines" of any sort whatsoever. Please e-mail responses to me directly, and if there is sufficient response I will post a summary! Dave Weeks Network Mgmt Eng. Centre tel: external: +44 (0)1 945-2607 STC Telecommunications Ltd fax: external: +44 (0)1 361-4535 Oakleigh Road South telex: 267757 STLTEL G New Southgate Bitnet: dpw%uk.co.stc.tcom@ukarcl London JANET: dpw@tcom.stc.co.uk N11 1HB UUCP: dpw@tcom.uucp OR dpw%tcom.uucp@uunet.uu.net U.K. ARPA: dpw%tcom.stc.co.uk@earn-relay.ac.uk
rfg@ics.uci.edu (Ron Guilmette) (02/08/90)
In article <2754@arran.tcom.stc.co.uk> dpw@tcom.stc.co.uk (David Weeks) writes: >This is a request for information on C++ coding "guidelines" of any sort >whatsoever. Please e-mail responses to me directly, and if there is >sufficient response I will post a summary! This sounds like a good project, and one we might all benefit from. I suggest starting from some existing set of C coding guidelines. Somebody please correct me if I am wrong, but didn't I see a set of C coding guidelines float by somewhere on net news not that long ago? Where did it come from? I can't remember now. Wasn't it AT&T or Bell Labs or Belcore or... A couple of minor personal preferences... Peter G. recently was ranting and raving that people should never define member functions within classes. I tend to agree. Regarding the extent to which inline functions should be used, I believe that there have been numerous comments here lately pointing out that the use of inline functions should be highly restricted. Some radicals among us (Who, me?) may say that inline functions should never be used. I am reminded of the ending of the movie 2010. I envision an alternative ending in which some mysterious God-like entity broadcasts a message to all of programmerkind: "All of these language features are your's except for inline functions. Attempt no usage thereof." I've obviously been watching too much late night TV. :-) // rfg
hansen@pegasus.ATT.COM (Tony L. Hansen) (02/09/90)
< Regarding the extent to which inline functions should be used, I believe < that there have been numerous comments here lately pointing out that the < use of inline functions should be highly restricted. Some radicals among < us (Who, me?) may say that inline functions should never be used. I am < reminded of the ending of the movie 2010. I think that the comments lately have been pointing out problems with some current implementations of inline functions: When the inline must be outlined, a static version will be created as needed in EVERY .o file where it is needed. When the .o's are combined, you suddenly have N occurrences of the static function which wastes considerable space. Now, there is nothing in this description of the problem which indicates a problem with the language feature. Instead, the real problem is that there's currently no implementation which causes those outlined static functions to be combined into a single function at link time. Here's a conceivable implementation for cfront+COFF/ELF-based systems: Cfront would produce two (or more) files for each .c file; the first is the C code for the user's code (call it usercode.c), and the second (and on) is the C code for each outlined static functions (call them outlined1.c through outlinedN.c). cc is run on all files, producing two (or more) .o's. These .o's are then combined into a single .o file with the following modification: the .text, .data and .bss sections of the outlined1.o through outlinedN.o files would be renamed .O1text, .O1data and .O1bss through .ONtext, .ONdata and .ONbss, and then stuck into usercode.o. (This is where COFF/ELF is required; I don't know any other a.out format which has arbitrarily-named sections.) Now the linker comes along. For each .o file, it pulls in the .text, .data and .bss sections as normally done. It then looks at the .O*text, .O*data and .O*bss sections and ONLY pulls it in if a symbol within it satisfies a currently-unresolved symbol. (Just as if that function had been found within a library.) Here's another implementation: Each .c which is compiled somehow produces a file which is treated just like a library file (a .a archive) by the linker except that the first .o in such archives is ALWAYS forced to be pulled in. Those people who have their own compilers and linkers and can control the format of the object file can do this easily enough by having optional sections at the end of the object file which are treated by the linker as optional (only load as needed). Tony Hansen att!pegasus!hansen, attmail!tony hansen@pegasus.att.com
rfg@ics.uci.edu (Ronald Guilmette) (02/10/90)
In article <4446@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: >I think that the comments lately have been pointing out problems with some >current implementations of inline functions: > > When the inline must be outlined, a static version will be created > as needed in EVERY .o file where it is needed. When the .o's are > combined, you suddenly have N occurrences of the static function > which wastes considerable space. > >Now, there is nothing in this description of the problem which indicates a >problem with the language feature. Instead, the real problem is that there's >currently no implementation which causes those outlined static functions to >be combined into a single function at link time. > >Here's a conceivable implementation for cfront+COFF/ELF-based systems: [...nice but unusable scheme for combining multiple static out-of-line functions into single copies deleted...] Tony, I believe that there are two serious problems with your scheme. First, some programmers out there have yet to "get religion" when it comes to avoiding the use of the preprocessor to do evil things. Thus, you might see the following code in a C++ header file someday: INLINE void foobar () { some_var = SOME_MACRO; } Now if you assume that INLINE gets defined to `static' and if you allow that this header file might get included by two or more "base" files, you should see that it is at least possible that during these two independent inclusions, the value of SOME_MACRO may take on two different values. If that were the case, then your suggested link-time optimization (to only pull in one of the two versions of `foobar') would be an "unsafe" optimization, because it would change the semantics of the resulting program. Another problem is that when the compiler decides to out-of-line a function that was declared as inline, the compiler drops the `inline' attribute of the function but leave it as `static'. Thus, your idea about the linker only pulling in the first available version to satisfy some outstanding `reference' does not make sense, because unsatisfied references are (by definition) for "externals" (i.e. extern) and never for `static' things. // rfg
gary@dgcad.SV.DG.COM (Gary Bridgewater) (02/10/90)
In article <4446@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: >< Regarding the extent to which inline functions should be used, I believe >< that there have been numerous comments here lately pointing out that the >< use of inline functions should be highly restricted. Some radicals among >< us (Who, me?) may say that inline functions should never be used. I am >< reminded of the ending of the movie 2010. If you don't like "inline" don't use it. If you don't want to see it, get a magic marker and 'remove' it from your manual. Making a religious issue out of it is counterproductive. Can "inline" be abused? Of course, but if that were an argument c would have died out long ago. Is it possible that there are c++ programmers, perhaps visitors from strange other languages, who know when/how to use inline? Yes. Even the c++ implementation? Maybe. >I think that the comments lately have been pointing out problems with some >current implementations of inline functions: > > When the inline must be outlined, a static version will be created > as needed in EVERY .o file where it is needed. When the .o's are > combined, you suddenly have N occurrences of the static function > which wastes considerable space. Whoops. Who said people that use "inline" care about wasted space? People who want inline want locality of reference and/or tight code. Not because its sexy, but because they need it. Let's just say that, in some instances, it can be very useful to reduce page faults as much as possible and having code purposely spread over multiple pages is anti-useful. What you go on to describe is something different but also useful. What you want is the "outline" statement. It's description would be "inline if possible to save code, else gather all references together to, again, conserve code". This is worth discussing further. Possible use - during debugging a piece of code that is readily inline-able has additional debugging statements #ifdef'd in. Since debugging is a fairly memory intensive activity anyway, conserving code via your scatter/gather compilation methods could be useful. -- Gary Bridgewater, Data General Corporation, Sunnyvale California gary@sv.dg.com or {amdahl,aeras,amdcad}!dgcad!gary The impossible we understand right away - the obvious takes a little longer.
franka@mentor.com (Frank A. Adrian) (02/11/90)
In article <4446@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: > [A bunch of stuff having to do with linkers and loaders to try to fix the > problem of C++ creating static copies of inline functions...] An even better solution is to just have the compiler generate inline code when you tell it to. Yes, I know that naive users can get screwed when code size balloons, but now naive users (and some experienced users) are getting screwed because of ballooning static inline copies. The arbitrary limit on inlining in cfront doesn't help at all to make it clear when things will be inlined and when things won't - I know, you get a warning, but that's small consolation. The arbitrary limit that cfront puts on inline complexity doesn't help at all. I want to use inline functions to replace macros. I can write arbitrarily complex macros (and have done so) to great benefit. Cfront does not allow this. If I get over a certain number of operators, if I construct enough objects in an inline, I'm screwed. DAMMIT, I KNOW WHEN I WANT SOMETHING INLINED AND ALSO WHEN I DON'T. Sorry for the flame, but it seems that a lot of C++'s problems are QUITE self-inflicted... -- Frank A. Adrian Mentor Graphics, Inc. franka@mntgfx.com
beard@ux1.lbl.gov (Patrick C Beard) (02/14/90)
In article <4446@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes:
#< Regarding the extent to which inline functions should be used, I believe
#< that there have been numerous comments here lately pointing out that the
#< use of inline functions should be highly restricted. Some radicals among
#< us (Who, me?) may say that inline functions should never be used. I am
#< reminded of the ending of the movie 2010.
#
#I think that the comments lately have been pointing out problems with some
#current implementations of inline functions:
#
# When the inline must be outlined, a static version will be created
# as needed in EVERY .o file where it is needed. When the .o's are
# combined, you suddenly have N occurrences of the static function
# which wastes considerable space.
Now hold on. The amount of space wasted by outlining inline functions
to static functions for every file that needs them will always be <= to
the code space taken by correctly inlining the function to begin with. And
will likely be much less. So this brings to mind some guidelines for
using inline member functions.
1. Inlines should be one line of code. [I use them mainly for read
only access to private or protected data].
2. Inlines should be simple.
One convention I use is that all my classes have a method called Error()
which returns the most recently encountered operating system error. Since
this just looks at the variable error stored in each instance, I always
define it as:
OSErr Error() { return error; }
-------------------------------------------------------------------------------
- Patrick Beard, Macintosh Programmer (beard@lbl.gov) -
- Berkeley Systems, Inc. ".......<dead air>.......Good day!" - Paul Harvey -
-------------------------------------------------------------------------------
roger@decvax.UUCP (Roger H. Scott) (02/16/90)
In article <4843@helios.ee.lbl.gov> beard@ux1.lbl.gov (Patrick C Beard) writes: >... >Now hold on. The amount of space wasted by outlining inline functions >to static functions for every file that needs them will always be <= to >the code space taken by correctly inlining the function to begin with. >And will likely be much less. This statement is so wrong I don't even know where to begin tearing it appart. First of all, AT&T's translators generate "outline" version of inline functions that *aren't even called*. Are you trying to tell me that the amount of code generated for these is <= 0? Second, the object code generated for a *real function* is likely to be *at least* several instructions bigger than the code that would be generated inline. Thirdly, in some cases the size difference is huge (bordering on infinite ratio-wise). Consider the following: typedef unsigned n32; class Set32 { // set of up to 32 small integers (0<=i<=31) unsigned b; public: Set32(n32 i0 =32, n32 i1 =32, n32 i2 =32, n32 i3 =32, n32 i4 =32, n32 i5 =3, n32 i6 =32, n3 i7 =32) : b (((i0<32)?(1<<i0):0) | ((i1<32)?(1<<i1):0) | ((i2<32)?(1<<i2):0) | ((i3<32)?(1<<i3):0) | ((i4<32)?(1<<i4):0) | ((i5<32)?(1<<i5):0) | ((i6<32)?(1<<i6):0) | ((i7<32)?(1<<i7):0)) { } ... }; ... void f(Set32); ... void g() { ... f(Set32(2, 3, 5, 7, 9)); // <<<======= ... } How much code do you think the construction of the Set32 object on the marked line takes? With the C compilers I have used the answer is, in effect, *none*. Cfront generates a huge, ugly *constant* expression which the C compiler constant-folds into a single value. Now, how much code do you think the outlined version of Set32::Set32() occupies? I'll give you a hint - it is a number *many* times 0 (or even 1!). > So this brings to mind some guidelines for using inline member functions. > > 1. Inlines should be one line of code. [I use them mainly for read > only access to private or protected data]. > 2. Inlines should be simple. Simple rules for simple minds. The real world isn't so neat and tidy - guidelines based on the computation involved are much more meaningful. It sounds to me like Mr. Beard is talking off the top of his head here and hasn't actually observed or measured the problem under discussion. Correct me if I'm wrong.
fox@allegra.att.com (David Fox) (02/17/90)
Patrick C Beard (beard@ux1.lbl.gov) writes: > > Now hold on. The amount of space wasted by outlining inline functions > to static functions for every file that needs them will always be <= to > the code space taken by correctly inlining the function to begin with. > And will likely be much less. An inline only takes up space if you use it. A static always takes up space. If you use it zero times (the usual case, I contend), you win. > So this brings to mind some guidelines for > using inline member functions. > > 1. Inlines should be one line of code. [I use them mainly for read > only access to private or protected data]. > 2. Inlines should be simple. I can't understand why people are so quick to tell people when and how to (or not to) use inline functions, and usually (as here) without any justification, apart from "they take up too much space". If you please, I'd like to be the judge of what is "too much space" on a case by case basis. Sometimes I'll make a piece of code into a subroutine that is only called once (or maybe twice), in order to elucidate the structure of the program. In this case it is appropriate to make even a hundred line function inline. Another reason I've heard for using inlines is to preserve locality of reference. These decisions should be up to programmers, not to guideline writers. David Fox fox@allegra.att.com -- We've all got opinions. Where do they come from?
pcg@aber-cs.UUCP (Piercarlo Grandi) (02/19/90)
In article <FOX.90Feb16162320@devo.allegra.att.com> fox@allegra.att.com (David Fox) writes:
Sometimes I'll make a piece of code into a subroutine that is only
called once (or maybe twice), in order to elucidate the structure of
the program. In this case it is appropriate to make even a hundred
line function inline.
Well, one of the main reasons for inlines does not apply; for a large
function, call return overhead is going to be insignificant. And doing
large inlines taxes the *compiler*. On the other hand, I admit to the same
practice (but only occasionally)... even if I think it is pretty pointless.
Another reason I've heard for using inlines is to preserve locality of
reference.
Or, even more strongly, allowing code simplification. But I could leave
to the programmer, actually.
These decisions should be up to programmers, not to guideline writers.
Hey, if you *know* what you are doing, a guideline is not a rule! :-).
Another thought: I actually think that inline could usefully be split in two
keywords; 'inlinable' applied to functions, and 'inline' applied to their
calls. It is not always worth it to inline expand a function at every one of
its calls. But maybe this is splitting hairs too finely...
--
Piercarlo "Peter" Grandi | ARPA: pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth | UUCP: ...!mcvax!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk
fox@allegra.att.com (David Fox) (02/19/90)
In article <1644@aber-cs.UUCP> pcg@aber-cs.UUCP (Piercarlo Grandi) writes:
These decisions should be up to programmers, not to guideline writers.
Hey, if you *know* what you are doing, a guideline is not a rule! :-).
I guess what I am objecting to is compilers that arbitrarily
decide that a function is "too big" and outline it for that
reason only.
David Fox
--
We've all got opinions. Where do they come from?
williams_j@apollo.HP.COM (Jim Williams) (02/23/90)
This brings up an important reason for using inlines. The example class I have is too long to be included here, but it contains a number of member functions, all declared "inline", which perform numerical calculations. By expanding these inline, the C compiler optimizer is able to eliminate the majority of these calculations because the results are never used. A lot of the rest of the calculations can be done at ("C") compile time because the complier knows the value of the arguments passed to the functions. The performance increase therefore far exceeds the overhead of the function call and may be closer to an order of magnitude. If these functions were not "inlined", some of the performance could be gotten back by adding some record keeping to the class so that it could be determined at run time which values actually needed to be calculated. This would add complexity, however. Also, I don't see any way to force computations to be done at compile time for non-inlined functions. My vote is that if a function is declared "inline", it should either be implemented inline, or if not possible, flagged as an error.
hansen@pegasus.ATT.COM (Tony L. Hansen) (02/23/90)
In article <25D3D824.15436@paris.ics.uci.edu> rfg@ics.uci.edu (Ronald Guilmette) writes: <In article <4446@pegasus.ATT.COM> hansen@pegasus.ATT.COM (Tony L. Hansen) writes: << I think that the comments lately have been pointing out problems with << some current implementations of inline functions: << When the inline must be outlined, a static version will be << created as needed in EVERY .o file where it is needed. When the << .o's are combined, you suddenly have N occurrences of the << static function which wastes considerable space. < < I believe that there are two serious problems with your scheme. First, < some programmers out there have yet to "get religion" when it comes to < avoiding the use of the preprocessor to do evil things. Thus, you might < see the following code in a C++ header file someday: < < INLINE void foobar () < { < some_var = SOME_MACRO; < } The cfront 2.0 Reference Manual states (section 3.3) "There must be exactly one definition for each function, object, and class in a program." In an environment such as cfront and g++ provide, this is almost impossible to detect or enforce. In other environments, it may be easy to detect and enforce. Tony Hansen att!pegasus!hansen, attmail!tony hansen@pegasus.att.com