Inline functions

I

Ian Collins

Actually, it's the primary reason for avoiding it. In a typical
development environment, the multiple-definition behavior
replaces a link-time error with truly undefined (and somewhat
random) behavior. Not something particularly desirable. The
fact that the code has to be in the header increases coupling.
Significantly if the function is non-trivial. The only
justification for having inline at all is performance.

Or if you wish to have a header only library.
And that some will be inlined even if the inline keyword is not
present. That's why the use has to be profiler driven.

Isn't that exactly what I said?
And how is that relevant?

Your last point (in parentheses) implied it was easily controllable,
when it often is not.
You are trying to optimize code.
Depending on the compiler, different techniques may or may not
be appropriate. Inline is a useful technique: it has the
advantage that it is very, very easy to use, and that it is
guaranteed to compile with the same semantics everywhere

Same semantics, yes. Same selection heuristics, no. One compiler may
inline a function another would not.
---you
don't need #ifndef's or whatever to use it. (Although you
might, if e.g. it results in the code running slower on some
other compiler.) If it works (i.e. the results become "fast
enough"), you win. If it doesn't, you haven't lost too much
time exploring a dead-end alley.

Assuming the compiler lets you do the exploration.
That's the ideal situation, and such compilers typically will
ignore the hint. Once such compilers become common place,
I imagine that inline will go the way of register. But we're
not there yet.

Maybe I'm spoilt by using tools that do support it. I had assumed it
was widely used.
 
A

Alf P. Steinbach /Usenet

* James Kanze, on 06.07.2010 11:55:
* James Kanze, on 05.07.2010 19:14:
[...]
Consider how a compiler would have to treat it in order to
inline everything that's technically 'inline', which for Boost
is most everything.
I was under the impression that the parts of Boost which are
header only were header only because they were templates, not
because they were inline.
Nobody's said that those parts (most of Boost) are header-only
because they're inline.
They're inline because they're header-only.

Except that the parts I looked at aren't inline, even when
they're header only.

On the contrary of your impression, the Boost parts that require separate
compilation are in general only those where there are system dependencies.

Most of the header only libraries are templates. I've not seen
that many inline functions in them; only for very trivial
things, where performance is clearly an issue, or for cases
where the function doesn't actually do anything except forward
to another function (and where it should disappear from the
generated code if it is inlined).

I've posted the examples I've seen that don't use inline
functions. Maybe you could mention one or two that use inline
functions in order to make the library header-only. I can't
find one.

Starting at "A", the non-template "Any" class is wholly inline.

But you're right that most of the Boost stuff is templated.

The point is that most places where there is a dependency on non-templated
stuff, that stuff is defined 'inline' (using that keyword or by defining member
functions directly in a class definition or by pseudo-templating and typedef,
which results in the same) in order to support the header-only design goal.


[snip]
Which compilers?

E.g. the two I use regularly, g++ and msvc.

I'm not using this stuff, so I don't go around remembering the details. I just
know about it in general. So I had to look it up for you, which took some time;
it'd be better if you looked up such things yourself, I think, and if you were
then unable to find anything, reporting that and /then/ asking.

// g++
inline void foo (const char) __attribute__((always_inline));

This causes g++ to attempt to inline the function for non-optimized build.

// g++
inline void foo (const char) __attribute__((gnu_inline));

This purportedly prevents g++ from emitting a linkable definition, i.e. always
inline.

// g++
inline void foo (const char) __attribute__((noinline));

This prevents the function from being machine-code-level inlined.

And there are some macros to support this stuff, plus some more general compiler
options, including some PC-specific options.

// msvc
class X
{
__declspec(noinline) int mbrfunc()
{
return 0;
} // will not inline
};

// msvc
class X
{
__forceinline int mbrfunc()
{
return 0;
} // will always inline
};

I wrote the last example off the cuff, not copied from docs; check it if you're
really interested in this stuff and not just asking questions willy-nilly.

The standard specifies a specific mechanism;
it's rather irresponsible for the compiler to decide to use
another one.

Since that POV doesn't square with reality there is presumably some assumption
that doesn't hold, yes?

Except that the issues concerning inline haven't changed since
then. The definition is the same as it was then (except that
the standard makes it clear that inline doesn't change semantics
or linkage---the original version of inline make the function
implicitly static).

Uhm, except for the difference there is no difference... Anyway, thanks!, I
didn't know about that. I thought all the difference was in the context, how the
language is used in modern programming (and hence what compilers do).


[snip]
It's spanned a fairly large number of application domains.

Yeah, but I think those application domains must have been similar in some
fundamental way. E.g. you're the only person I know who uses the Boehm garbage
collector regularly. Which I believe influences the design of things.


Cheers & hth.,

- Alf
 
J

James Kanze

* James Kanze, on 06.07.2010 11:55:
* James Kanze, on 05.07.2010 19:14:
[...]
Consider how a compiler would have to treat it in order to
inline everything that's technically 'inline', which for Boost
is most everything.
I was under the impression that the parts of Boost which are
header only were header only because they were templates, not
because they were inline.
Nobody's said that those parts (most of Boost) are header-only
because they're inline.
They're inline because they're header-only.
Except that the parts I looked at aren't inline, even when
they're header only.
On the contrary of your impression, the Boost parts that
require separate compilation are in general only those where
there are system dependencies.

What are the system dependencies in boost::format, or
boost::regex?
Starting at "A", the non-template "Any" class is wholly inline.

Maybe the author thought it needed the performance boost? (I
don't know. But most of the functions look pretty trivial, so
the author might have assumed that inline would provide
a significant performance boost.)
But you're right that most of the Boost stuff is templated.
The point is that most places where there is a dependency on
non-templated stuff, that stuff is defined 'inline' (using
that keyword or by defining member functions directly in
a class definition or by pseudo-templating and typedef, which
results in the same) in order to support the header-only
design goal.

I don't know. I've not looked at enough to say "most". Most of
my uses of Boost have been the templated stuff like bind, where
of course, inlining would be used because you want the actual
functions to disappear in the generated code (since they are
used for compiler internal logic, and not to do anything).
[snip]
Which compilers?
E.g. the two I use regularly, g++ and msvc.

G++ doesn't. On the other hand, g++ inlines any function whose
definition is visible, so it doesn't make much difference.
I'm not using this stuff, so I don't go around remembering the
details. I just know about it in general. So I had to look it
up for you, which took some time; it'd be better if you looked
up such things yourself, I think, and if you were then unable
to find anything, reporting that and /then/ asking.
// g++
inline void foo (const char) __attribute__((always_inline));
This causes g++ to attempt to inline the function for non-optimized build.
// g++
inline void foo (const char) __attribute__((gnu_inline));
This purportedly prevents g++ from emitting a linkable
definition, i.e. always inline.

Both of which are more than just a hint (especially the second).
// g++
inline void foo (const char) __attribute__((noinline));
This prevents the function from being machine-code-level inlined.

G++ offers other options than just straight "inline". But
they're only needed in special cases---normally, for
optimization, you specify inline. In the case of g++, it works
more or less as expected.
And there are some macros to support this stuff, plus some
more general compiler options, including some PC-specific
options.
// msvc
class X
{
__declspec(noinline) int mbrfunc()
{
return 0;
} // will not inline
};
// msvc
class X
{
__forceinline int mbrfunc()
{
return 0;
} // will always inline
};
I wrote the last example off the cuff, not copied from docs;
check it if you're really interested in this stuff and not
just asking questions willy-nilly.

Again, both your examples do more than just "inline". I think
that "inline" in MSVC works pretty much as the committee
intended as well: you aren't guaranteed that the function will
be inlined, but if the compiler can reasonably do so, it will.
Since that POV doesn't square with reality there is presumably
some assumption that doesn't hold, yes?

The compilers I've familiar with (MSVC, g++ and Sun CC) do take
"inline" to be a serious hint, and respect it. Which
corresponds to the committee's expressed intention: "The inline
specifier indicates to the implementation that inline
substitution of the function body at the point of call is to be
preferred to the usual function call mechanism."
Uhm, except for the difference there is no difference...
Anyway, thanks!, I didn't know about that. I thought all the
difference was in the context, how the language is used in
modern programming (and hence what compilers do).

Compilers do what they've always done with regards to inline.
(Well, actually, the respect it a lot more than they used to.
Some of the earlier compilers wouldn't inline a function which
contained a loop.) Nothing has changed with respect to inline
since the original version of the standard has been adopted.
(And it is still banned by most coding guidelines, except in
exceptional cases.)
[snip]
It's spanned a fairly large number of application domains.
Yeah, but I think those application domains must have been
similar in some fundamental way. E.g. you're the only person
I know who uses the Boehm garbage collector regularly. Which
I believe influences the design of things.

Actually, I know people who use the Boehm collector more than
I do. A lot of my work involves contexts where I can't use it,
for various reasons.

The only real common characteristic of my work has been that
most of the projects involved a fairly large number of people.
So code had to be written in ways that made it easier to
understand and maintain. Which leads to avoiding inline as much
as possible (and avoiding templates in a lot of cases, as well,
since they suffer from the same problem).
 
A

Alf P. Steinbach /Usenet

* James Kanze, on 06.07.2010 19:56:
On Jul 6, 2:58 pm, "Alf P. Steinbach /Usenet"<alf.p.steinbach


What are the system dependencies in boost::format, or
boost::regex?

As far as I know boost::format is a header-only sub library.

The sub-libraries that require separate compilation are, as far as I know,
date_time, filesystem, graph, iostreams, program_options, regex, serialization,
signals, system, test and thread.

For regex, which you're as asking about, the system dependencies include code like


<code file="libs/regex/src/w32_regex_traits.cpp>
#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
# define NOMINMAX
#endif
#define NOGDI
#include <windows.h>

#if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(UNDER_CE)
#pragma comment(lib, "user32.lib")
#endif
</code>


Again, as with your previous posting I'd much prefer that you checked out things
yourself and only asked after failing to find the relevant info, wasting /your/
time instead of mine.

That is, hopefully this is not insulting, because I do respect you, but RTFM, James.

I've snipped the rest of your posting since it consists mostly of just
reassertions of your earlier points. I'm not interested in endlessly providing
facts etc. only to have them ignored and earlier beliefs reasserted. Regarding
Boost you've got my statement, you've got Boost documentation cited, you've got
examples as you've asked for, etc., but nothing is good enough, in particular
reality is not good enough: you just reassert. So I snipped the rest.


Cheers & hth.,

- Alf
 
G

Gil

g++ with optimizations turned on doesn't treat inline keyword lightly
and it has just a handful of reasons not to honor it: setjmp/longjmp,
alloca, non local goto, __builtin_return etc in the body or variable
argument list or some language hook checks and size limitations.

most of the time boost-ers are using inline keyword for both reasons:
provide header only libraries and exploit the continuously developing
inline heuristics of modern compilers. it's a win-win situation
because compilers are smart enough to take the inline decision on
their own whilst always obeying the linkage constraint.
 
A

Anand Hariharan

Isn't that exactly what I said?

Not at all to nitpick, but you wrote "unlined". From your follow-up,
it seems like that was a typo. I can't speak for James, but I assumed
you meant "not inlined" i.e., "Odds are [that] [some] functions will
[not] be [inlined] whether the inline keyword is present or not."

- Anand
 
J

James Kanze

* James Kanze, on 06.07.2010 19:56:
As far as I know boost::format is a header-only sub library.

I think so too. But most of the functions are not inline. It's
header-only because its a template.

[...]
That is, hopefully this is not insulting, because I do respect
you, but RTFM, James.

:)

With regards to the initial question (the significance of
"inline"), the "manual" is the C++ standard, and it says exactly
what I've been arguing.

With regards to current programming practice, it's hard to be
precise, because of course, neither of us knows the entire body
of code being written. But even within Boost, I can't find
anything expressing "header-only" as a goal, with
a recommendation to use "inline" in order to achieve it. My
impression is more that it is an undesirable side effect of the
fact that most of the code is templates. Having the
implementation code in header files certainly conflicts with all
accepted standards for good development processes, and in fact,
makes some of the Boost librarys (e.g. Jason) almost unusable
with MSVC (because the compile times quickly become unbearable).
 
J

James Kanze

On 07/ 6/10 10:05 PM, James Kanze wrote:
Or if you wish to have a header only library.

Who would wish to have a header only library?

This insistence on header-only libraries is curious. One of the
big motivations for choosing C++ over, say Java, is that C++
allows this separation, with the implementation in a separate
file from the class definition, compiled and linked once (in an
environment that you control and can easily reproduce). One of
the big drawbacks with using templates is that in practice, you
loose this advantage.
Isn't that exactly what I said?

I'm not sure. What did you mean by "unlined"?
Your last point (in parentheses) implied it was easily controllable,
when it often is not.

When you're optimizing, you're concerned with the generated code
(and not just the semantics of the generated code). That's
never really easily controllable from a high level language. In
practice, most mainline compilers do inline a function declared
inline, at least in most circumstances, so in practice, you have
a fair bit of control. But as always when optimizing, you have
to profile before *and* after; modern compilers sometimes work
in strange ways, and any optimization step may in fact have no,
or even a negative, working. (Even when the compiler does
inline the function, the results may be slower than without it
being inlined.)
Same semantics, yes. Same selection heuristics, no. One
compiler may inline a function another would not.

Which is true for just about any optimization technique you care
to talk about.
Assuming the compiler lets you do the exploration.

? I don't know of any compiler which will refuse to compile an
inline function.
Maybe I'm spoilt by using tools that do support it. I had assumed it
was widely used.

Which tools are those? Most compilers today to use profiler
feedback, but very few have reached the point where they can
determine better than a good programmer which functions need
inlining (although I think some, e.g. Sun CC, are very close).
 
I

Ian Collins

I'm not sure. What did you mean by "unlined"?

It was a typo. I'm hopeless at spotting my own and I haven't found a
suitable unit test framework for Usenet posts!
When you're optimizing, you're concerned with the generated code
(and not just the semantics of the generated code). That's
never really easily controllable from a high level language. In
practice, most mainline compilers do inline a function declared
inline, at least in most circumstances, so in practice, you have
a fair bit of control.

True, but they will still apply their own rules. For example may will
not inline a function over a certain size and many inline most functions
(hint or not) at certain optimisation levels.
Which is true for just about any optimization technique you care
to talk about.

True, and like most optimisations the compiler will use it without a
hint from the programmer.
? I don't know of any compiler which will refuse to compile an
inline function.

But will they always follow the hint?
Which tools are those? Most compilers today to use profiler
feedback, but very few have reached the point where they can
determine better than a good programmer which functions need
inlining (although I think some, e.g. Sun CC, are very close).

That one!
 
I

Ian Collins

Who would wish to have a header only library?

I do, but only for collections of small utility classes or functions
that are obvious candidates for inline. I guess I could rely on the
compiler and linker to do the inline with inter-procedural analysis, but
I don't know how many can do that (and it slows down builds).
This insistence on header-only libraries is curious. One of the
big motivations for choosing C++ over, say Java, is that C++
allows this separation, with the implementation in a separate
file from the class definition, compiled and linked once (in an
environment that you control and can easily reproduce). One of
the big drawbacks with using templates is that in practice, you
loose this advantage.

It is more of a convenience than an insistence. It's nice with C++ to
be given the choice.
 
I

Ian Collins

Anybody who wishes to write generic code and use templates would wish to
have a header only library, the STL is mostly a header only library.
What have you got against templates? Templates are one of the things
that makes C++ great.

That quote was taken out of context. We were discussing inline
functions and I suggested header only libraries as one use. With many
compilers template libraries are header only is a necessity, but
building non-template header only libraries is a programmer choice.
Not "curious" but common sense and C++ mainstream. Dissing templates is
a pointless exercise. Use templates when appropriate and don't use them
when inappropriate. :)

Who's "dissing" templates?
 
C

cpp4ever

* James Kanze, on 06.07.2010 19:56:
As far as I know boost::format is a header-only sub library.

I think so too. But most of the functions are not inline. It's
header-only because its a template.

[...]
That is, hopefully this is not insulting, because I do respect
you, but RTFM, James.

:)

With regards to the initial question (the significance of
"inline"), the "manual" is the C++ standard, and it says exactly
what I've been arguing.

With regards to current programming practice, it's hard to be
precise, because of course, neither of us knows the entire body
of code being written. But even within Boost, I can't find
anything expressing "header-only" as a goal, with
a recommendation to use "inline" in order to achieve it. My
impression is more that it is an undesirable side effect of the
fact that most of the code is templates. Having the
implementation code in header files certainly conflicts with all
accepted standards for good development processes, and in fact,
makes some of the Boost librarys (e.g. Jason) almost unusable
with MSVC (because the compile times quickly become unbearable).

Hmmmm, if what you say about the Boost libraries is true, that
is worrying. Although if your boost usage is encapsulated within
application classes, I wonder whether this would alleviate the problem,
(it's what I try to do). Can I assume this could also affect MAC and
Linux development? There is at least one good reason for having "inline"
implementation, speed. Although this can create code bloat, that is not
so much of a problem in these days of memory amply available.
So, how do others handle these type of problems? Perhaps it should be a
new topic.

cpp4ever
 
Ö

Öö Tiib

I think so too.  But most of the functions are not inline.  It's
header-only because its a template.
    [...]
That is, hopefully this is not insulting, because I do respect
you, but RTFM, James.

With regards to the initial question (the significance of
"inline"), the "manual" is the C++ standard, and it says exactly
what I've been arguing.
With regards to current programming practice, it's hard to be
precise, because of course, neither of us knows the entire body
of code being written.  But even within Boost, I can't find
anything expressing "header-only" as a goal, with
a recommendation to use "inline" in order to achieve it.  My
impression is more that it is an undesirable side effect of the
fact that most of the code is templates.  Having the
implementation code in header files certainly conflicts with all
accepted standards for good development processes, and in fact,
makes some of the Boost librarys (e.g. Jason) almost unusable
with MSVC (because the compile times quickly become unbearable).

        Hmmmm, if what you say about the Boost libraries is true, that
is worrying. Although if your boost usage is encapsulated within
application classes, I wonder whether this would alleviate the problem,
(it's what I try to do). Can I assume this could also affect MAC and
Linux development? There is at least one good reason for having "inline"
implementation, speed. Although this can create code bloat, that is not
so much of a problem in these days of memory amply available.
        So, how do others handle these type of problems? Perhaps it should be a
new topic.

I look at boost as pile of tools. Code is on my hard drive, several
versions even. So there is a chainsaw. Should dentist use this
excellent chainsaw? Maybe not. It can not be decided that if something
is in boost then look no further, that has to be taken.

As for such problems, deal case-by-case. For example <boost/
noncopyable.hpp>. 37 lines. Can it make build times grow out of the
window? Maybe not. So build time should not be considered as problem
with boost for someone who uses only boost::noncopyable.
 
J

Jeff Flinn

James said:
... and in fact,
makes some of the Boost librarys (e.g. Jason) almost unusable
with MSVC (because the compile times quickly become unbearable).

Oddly enough I (actually Christoffe Henry, author of boost's
meta-state-machine library), have found the major culprit is MSVC's /Gm
switch. This "Enable Minimal Rebuild" option which ironically is
supposed to speed up builds causes template heavy code to compile
much-much-much slower. Some of my files that took 2-1/2 minutes to
compile now take less than 7 seconds.

Jeff
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,177
Latest member
OrderGlucea
Top