[comp.lang.c++] Inline functions

larry@zeek.UUCP (Larry Podmolik) (04/06/89)

I have a question concerning inline functions: where should they be
placed?  I don't like putting the body of the function in the class
declaration, since it makes the class "interface" harder to read,
especially if you don't care HOW a routine is implemented.

On page 266, Bjarne says:

	The _inline_ specifier is only a hint to the compiler,
	does not affect the meaning of the program, and may be
	ignored.

If the inline functions are defined in the class declaration (.h
file), then they get included wherever that .h file does.  Fine.
But say you put them in the corresponding .c file with the "normal"
function definitions.  Since you are compiling modules separately,
how does the compiler figure out how to do inline expansion of the
function body?  In this case, do they _have_ to be treated as
regular functions (i.e., _inline_ ignored)?  And if you put them
in the .h file, which is included in several modules, and the
compiler decides to treat them as regular functions, won't that
cause problems when linking (multiple redefinitions of the same
function)?

This came up when I was adapting the String class example on pp. 184 of
Bjarne's book.  (AT&T C++ 1.2, 3B2/400 SVR3.0) The stuff on p. 184 was
in String.h, except that I removed the function bodies for the
operator functions:

    // String.h
    // other stuff...
    class String  {
         /* ... */
    friend int operator==(String&, String&);
    friend int operator==(String&, char*);
    friend int operator!=(String&, String&);
    friend int operator!=(String&, char*);
    };     // end of class String

Then in String.c, I put the definitions for these:

     // String.c
     #include "String.h"
     // stuff deleted...
     inline int operator==(String &x, String &y)
       { return strcmp(x.p->s, y.p->s) == 0; }
     inline int operator==(String &x, char *s)
       { return strcmp(x.p->s, s) == 0; }
     
     inline int operator!=(String &x, String &y)
       { return strcmp(x.p->s, y.p->s) != 0; }
     inline int operator!=(String &x, char *s)
       { return strcmp(x.p->s, s) != 0; }

This compiled fine, as did the main test program, but I got the following
linker errors:

	     CC -o main main.o String.o
     cc   -o main  main.o String.o -lC
     undefined			first referenced
      symbol  			    in file
     _eqFRCString__PC__                  main.o
     _eqFRCString__RCString___           main.o
     _neFRCString__RCString___           main.o
     ld fatal: Symbol referencing errors. No output written to main
     *** Error code 13

     Stop.

The same errors happened if I put the inline function definitions at
the bottom of String.h.  What am I doing wrong??

Any help appreciated.

-Larry

larry@zeek.UUCP (Larry Podmolik) (04/06/89)

Forgot to mention one thing: I looked at the output of

	CC -Fc String.c

and there was NO coade generated in the places where the inline
functions were defined.  No wonder the linker couldn't find them!!

Why did cfront replace these inline function with NOTHING??

-Larry

ech@pegasus.ATT.COM (Edward C Horvath) (04/07/89)

From article <225@zeek.UUCP>, by larry@zeek.UUCP (Larry Podmolik):
> I have a question concerning inline functions: where should they be
> placed?  I don't like putting the body of the function in the class
> declaration, since it makes the class "interface" harder to read,
> especially if you don't care HOW a routine is implemented.
 
> On page 266, Bjarne says:
 
> 	The _inline_ specifier is only a hint to the compiler,
> 	does not affect the meaning of the program, and may be
> 	ignored.

You over-interpreted bs's statement: the compiler may elect to compile a
genuine function for an inline, or may elect to expand the function call
into the function body.  However, the latter option is available ONLY if
the body of the function appears in the interface file, and cfront always
chooses the latter option...thus your inline functions are nil.

If you want a genuine function, move the body to the implementation (as you
have already done) and remove the inline keyword from the interface file.

Apparently you missed the point of inline: it is intended to replace the
baroque #define's used by many C programmers with a somewhat better-
behaved construct.  An inline-expanded function is faster (no argument
pushing, no stackframe buildup/teardown, no jsr/rts) but generally costs
more code space (every invocation becomes a copy of the body).

I hope that clears things up a bit.  The "unclean" appearance of a function
body in the interface file is properly regarded as a wart on the language.

=Ned Horvath=

bright@Data-IO.COM (Walter Bright) (04/08/89)

In article <225@zeek.UUCP> larry@zeek.UUCP (Larry Podmolik) writes:
<I have a question concerning inline functions: where should they be
<placed?  I don't like putting the body of the function in the class
<declaration, since it makes the class "interface" harder to read,
<especially if you don't care HOW a routine is implemented.

Hurrah! Somebody with good style! Put the inline function bodies at
the end of the .h file, preceding them with a formfeed and a comment
saying the rest is implementation dependent.

<And if you put [inlines]
<in the .h file, which is included in several modules, and the
<compiler decides to treat them as regular functions, won't that
<cause problems when linking (multiple redefinitions of the same
<function)?

If a function can't be inlined, it is made static. The unfortunate
result is that you wind up with a copy in each object file in which
the inlined function is referred to. Though that is probably not worse
size-wise than if they were inline expanded.

Moral: For best results, restrict your use of inlines to *small* functions
where there really is a benefit. Example:

	class abc
	{	int def;
	    public:
		inline int getvalue();
	};

	/* Implementation follows	*/

	int abc::getvalue() { return def; }

mgardi@watdcsu.waterloo.edu (M.Gardi - ICR) (04/10/89)

There was a comment made as a follow up to this article about where inline
function declarations should occur, and what constituted good style.  It 
seems that the suggested method followed the design suggested by
Peter A, Kirslis in the 1987 Usenix C++ papers entitled:
A style for Writing C++ classes.
 
It might be a good idea to browse this short, concise article.



Peter Devries
Mutual Life of Canada (519) 888-2957
c/o mgardi@watdcsu