[comp.lang.c++] Request for C++ coding "guidelines"

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