Can anyone tell me the main difference between an inline function and recursive function?
These are unrelated concepts.
An function may be declared inline, which signals to the compiler that any calls to the function should be replaced by an implementation of the function directly at the point the call is made. It's vaguely like implementing some piece of logic as a macro, but it retains the clean semantics of a normal function call.
A recursive function is simply one that calls itself.
Note that the inline keyword is just a suggestion. The compiler is free to ignore it whenever it wants.
Also note that a recursive can also be declared inline. The compiler may, in principle, be able to inline a recursive function by transforming it into an iterative algorithm inside the calling function. However, recursion is usually one of the things that will make a compiler give up on inlining.
These are two very different concepts.
99% of programming languages allow recursive functions. A recursive function re-calls it's self to get something done. Most recursive functions can be rewritten as loops.
E.g. Simple recursive function.
int Factorial(int f)
{
if(f > 1)
return f * Factorial(f-1);
else
return 1;
}
An in-lined a function is a hint to the compiler that you don't want the processor to jump to this function, instead just include the op-codes for the function where ever it is used. This builds faster code for some calls one some architectures.
Be aware that most modern compilers targeting non-embedded processors will choose to ignore your "inline" hints, and will choose what to inline itself.
Hope this helps, apologies if badly formatted, typed on my I-phone.
A recursive function is a function that calls itself.
An inlined function is a function, that is "inserted into another function", i.e. if you have an inlined function add(a,b), and you call it from a function func, the compiler may be able to integrate the function body of add into the body of func so the arguments don't need to be pushed onto the stack.
Related
My understanding is that for compiled languages such as C++, the compiler substitutes the line where the functions are called for the statements in the function body.
Why then, is there a difference between functions and procedures ? Since, a procedure is changing state in-line and so are functions, once compiled ?
pseudocode:
main()
{
let a = 1;
a = add_one(a);
}
fn add_one(n) {
n + 1
}
at compile time, something like... (apologies, attempting to write pseudocode from my memory of that assembly class ~10 years ago is hard)
ASSIGN 1 to A
ASSIGN A FN ADDONE A
FN ADDONE A // Essentially, the function is converted into a procedure
A + 1 // That is evaluated and substituted in-line
EXIT
the compiler substitutes the line where the functions are called for the statements in the function body
That is something a compiler can optionally perform, known as "procedural integration", or more commonly "inlining".
Inlining is not the normal way of implementing procedure calls. Firstly, inlining all calls would cause compiled programs to explode in size, and potentially to run slower. (Inlining can speed up programs, but only when judiciously applied: an example of where it may help is when a small function that is executed many times in a loop is hoisted into that loop.)
Secondly, calls can be recursive. Recursion cannot be implemented by inlining; it is logically impossible for a function to be inserted into itself: this leads to infinite regress.*
The bare essence of a procedure call is that the calling procedure is suspended, while the called procedure executes. When the called procedure finishes executing, the caller is resumed. This semantics is preserved under inlining; it still looks like the surrounding procedure is suspended while the inlined one executes.
A regular non-inlined procedure call compiles into some kind of control transfer, whereby the machine, instead of executing the next instruction, is told to "jump" to some other list of instructions, corresponding to the body of the procedure. The previous location is somehow remembered. When the called procedure finishes, it "jumps" back to the remembered location, so the calling procedure resumes from that point. When multiple places in the program call a non-inlined procedure, they all share the same image of that procedure: the same list of instructions.
Both procedures and pure functions are susceptible inlining optimizations; there is no difference in that regard. The semantics is preserved; the inlined call appears to be passing parameters and returning a value.
The terminology like procedure and function varies from programming language to programming language.
How the words are used in computer science is that a function corresponds to the mathematical concept of a pure mapping from one abstract space to another. A function returns a value that is calculated from some arguments, which is done without side effects.
A procedure is a name given to some steps which perform some effects, making changes to the state of the machine. Those steps are invoked by their name. Procedures may look like functions in that they have arguments, and return values.
Some languages, like C, call everything function: printf is called a "function", even though it has a side effect of performing output. exit and abort are "functions", though they destroy the process and do not return.
When procedures are called functions, you may hear the term "pure function"
in reference to functions that don't have side effects and only calculate a value.
Common Lisp uses the function terminology similarly to C; both functions and procedures are defined using defun and are called functions. Scheme uses the term "procedure". So even related language dialects don't necessarily agree.
You have to keep the concepts clearly separated from the way your programming language documentation refers to them. Don't assume that because your language reference manual says "function", that it's talking about a pure mapping between sets.
(There are subtleties in the "function" concept because in computer science, which is after all a branch of mathematics, "function" can refer to a mathematical function, or to a computational function which calculates some mathematical function using concrete algorithmic steps. The two are not the same because not all mathematical functions are computable by a corresponding computational function. For instance the "halting function" exists in mathematics, but cannot be computed. The halting function H has two arguments: a program P and an input I. It maps these to a Boolean value: true if the program P halts when given input I, or false if it doesn't halt. The mathematical function is real because every P(I) pair either halts or doesn't halt. But we cannot implement such a function.)
* Of course, partial inlining of recursion is possible. For instance, in the simple case of a function calling itself, a compiler could decide to inline some of the self-calls to some specific depth. The inlining will "bottom out", so that some of the calls remain non-inlined.
I'm wondering if C++ will still obey the inline keyword when a function is passed as an agument. In the following example, would a new frame for onFrame be pushed onto the stack every time frame() is called in the while loop?
bool interrupt = false;
void run(std::function<void()> frame) {
while(!interrupt) frame();
}
inline void onFrame() {
// do something each frame
}
int main() {
run(onFrame);
}
Or would changing to this have any effect?
void run(std::function<inline void()> frame) {
while(!interrupt) frame();
}
If you have no definitive answer, can you help me find a way to test this? Possibly using memory addresses or some sort of debugger?
It's going to be pretty hard for the compiler to inline your function if it has to go through std::function's type-erased dispatch to get there. It's possible it'll happen anyway, but you're making it as hard as possible. Your proposed alternative (taking a std::function<inline void()> argument) is ill-formed.
If you don't need type erasure, don't use type erasure. run() can simply take an arbitrary callable:
template <class F>
void run(F frame) {
while(!interrupt) frame();
}
That is muuch easier to inline for the compiler. Although, simply having an inline function does not in of itself guarantee that the function gets inlined. See this answer.
Note also that when you're passing a function pointer, that also makes it less likely to get inlined, which is awkward. I'm trying to find an answer on here that had a great example, but until then, if inlining is super important, wrapping it in a lambda may be the way to go:
run([]{ onFrame(); });
still obey the inline keyword ... would a new frame ... be pushed onto the stack
That isn't what the inline keyword does in the first place (see this question for extensive reference).
Assuming, as Barry does, that you're hoping to persuade the optimiser to inline your function call (once more for luck: this is nothing to do with the inline keyword), function template+lambda is probably the way to go.
To see why this is, consider what the optimiser has to work with in each of these cases:
function template + lambda
template <typename F>
void run(F frame) { while(!interrupt) frame(); }
// ... call site ...
run([]{ onFrame(); });
here, the function only exists at all (is instantiated from the template) at the call site, with everything the optimizer needs to work in scope and well-defined.
Note the optimizer may still reasonably choose not to inline a call if it thinks the extra instruction cache pressure will outweigh the saving of stack frame
function pointer
void run(void (*frame)()) { while(!interrupt) frame(); }
// ... call site ...
run(onFrame);
here, run may have to be compiled as a standalone function (although that copy may be thrown away by the linker if it can prove no-one used it), and same for onFrame, especially since its address is taken. Finally, the optimizer may need to consider whether run is called with many different function pointers, or just one, when deciding whether to inline these calls. Overall, it seems like more work, and may end up as a link-time optimisation.
NB. I used "standalone function" to mean the compiler likely emits the code & symbol table entry for a normal free function in both cases.
std::function
This is already getting long. Let's just notice that this class goes to great lengths (the type erasure Barry mentioned) to make the function
void run(std::function<void()> frame);
not depend on the exact type of the function, which means hiding information from the compiler at the point it generates the code for run, which means less for the optimiser to work with (or conversely, more work required to undo all that careful information hiding).
As for testing what your optimiser does, you need to examine this in the context of your whole program: it's free to choose different heuristics depending on code size and complexity.
To be totally sure what it actually did, just disassemble with source or compile to assembler. (Yes, that's potentially a big "just", but it's platform-specific, not really on-topic for the question, and a skill worth learning anyway).
Compile for release and check the list files, or turn on disassembly in debugger. Best way to know is to check the generated code.
Under What condition an inline function ceases to be an inline function and acts as any other function?
The Myth:
inline is just a suggestion which a compiler may or may not abide to. A good compiler will anyways do what needs to be done.
The Truth:
inline usually 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. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules(especially w.r.t One Definition Rule) for inline are followed.
Under What condition an inline function ceases to be an inline function and acts as any other function?
Given the quoted fact there is a deeper context to this question.
When you declare a function as static inline function, the function acts like any other static function and the keyword inline has no importance anymore, it becomes redundant.
The static keyword on the function forces the inline function to have an internal linkage.(inline functions have external linkage)
Each instance of such a function is treated as a separate function(address of each function is different) and each instance of these functions have their own copies of static local variables & string literals(an inline function has only one copy of these ).
It's at the discretion of the compiler.
But some cases just can't be inlined, like:
Recursive functions
Functions whose address is referenced somewhere
Virtual functions (there are some exceptions thought)
That depends on the compiler optimization.
Different compilers have different rules to make the code more efficient. But if you declare a function as inline, the compiler tends to respect your decision as long as none of it's rules says different.
Remember that the compiler can change completely the execution path of a method. For example, consider the next situation:
int MyClass::getValue()
{
return someVariable;
}
At compile time, there is little difference between declaring this kind of function as inline or not. Probably the compiler will make the attribute partially public and code:
myInstance->getValue()
as
myInstance->someVariable
So it's more an aesthetical decision in most cases.
Im studying inline functions in C++ and have come to a section concerning limitations of its use. It says:
The compiler also cannot perform
inlining if the address of the
function is taken implicitly or
explicitly.
Can someone explain to me, perhaps with an example of some sort, what exactly this means?
You can mark any function as inline. Even a virtual function, even a recursive function, even a veeery veery long function, even if its address is taken. The main difference between an inline and non-inline function is that the definition of the former must appear in every translation unit (aka source file) in which it is used ( that's why inline functions are usually defined in the .h file), whereas the latter must be defined only once. You can use the inline function in every way that you can use a non-inline one.
The actual inlining part is up to the compiler. It can ignore your request, if, for example, your function is recursive or too long. On the other hand, the compiler may choose to inline a function which you haven't actually marked as inline.
There are two somewhat separate decisions the compiler makes concerning function inlining:
whether a particular function call is inlined;
whether a non-inline version of the function exists.
The first is decided by the compiler on a case-by-case basis, if inlining is possible at that point. It won't be possible if the function is virtual, or called through a function pointer, and it can't determine at compile time which function is to be called. It won't be possible if the definition is not available to the compiler, perhaps because it is defined in a different translation unit and the compiler does not do "whole program optimisation". The decision may, or may not, be influenced by whether the function is declared inline, and other factors such as its size and how often it is called.
The second depends on whether a non-inline version is required. It will be required if any call to it is not inlined. It will also (as per your quotation) be required if anything needs the address of the function, as then it must have an address. This can happen either directly (for example by assigning the address to a function pointer), or indirectly (for example, virtual functions will need their address stored somewhere to look up at runtime according to the object's dynamic type).
The existence of the non-inline version will not prevent any particular call to the function from being inlined, although it's possible that it might influence the compiler's decision, particularly if it's configured to optimise for code size.
To summarise, your quotation is simplistic and not entirely accurate; the compiler can still "perform inlining" if the address is taken, it just can't omit the non-inline version.
It's just wrong: ability to inline a function call is not affected by computing 2+2 or by taking the address of the function somewhere.
Which book or article are you reading?
On the other hand, if the address is taken then it might be practically impossible to remove the separate machine code function.
Cheers & hth.,
The key reason this works is that for_each () doesn’t actually assume
its third argument to be a function.
It simply assumes that its third
argument is something that can be
called with an appropriate argument. A
suitably defined object serves as well
as – and often better than – a
function. For example, it is easier to
inline the application operator of a
class than to inline a function passed
as a pointer to function.
Consequently, function objects often
execute faster than do ordinary
functions. An object of a class with
an application operator (§11.9) is
called a functionlike object, a
functor, or simply a function object.
[Stroustrup, C++ 3rd edition, 18.4-last paragraph]
I always thought that the operator
( ) call is just like function call
at runtime. how does it differ from
a normal function call?
Why is it easier to inline the
application operator than a normal
function?
How are they faster than function
call?
Generally, functors are passed to templated functions - if you're doing so, then it doesn't matter if you pass a "real" function (i.e. a function pointer) or a functor (i.e. a class with an overloaded operator()). Essentially, both have a function call operator and are thus valid template parameters for which the compiler can instantiate the for_each template. That means for_each is either instantiated with the specific type of the functor passed, or with the specific type of function pointer passed. And it's in that specialization that it is possible for functors to outperform function pointers.
After all, if you're passing a function pointer, then the compile-type type of the argument is just that - a function pointer. If for_each itself is not inlined, then this particular for_each instance is compiled to call an opaque function pointer - after all, how could the compiler inline a function pointer? It just knows its type, not which function of that type is actually passed - at least, unless it can use non-local information when optimizing, which is harder to do.
However, if you pass a functor, then the compile-time type of that functor is used to instantiate the for_each template. In doing so, you're probably passing a simple, non-virtual class with only one implementation of the appropriate operator(). So, when the compiler encounters a call to operator() it knows exactly which implementation is meant - the unique implementation for that functor - and now it can inline that.
If your functor uses virtual methods, the potential advantage disappears. And, of course, a functor is a class with which you can do all kinds of other inefficient things. But for the basic case, this is why it's easier for the compiler to optimize & inline a functor call than a function pointer call.
Summary
Function pointers can't be inlined since while compiling for_each the compiler has only the type of
the function and not the identity of the function. By contrast, functors can be inlined since even though the compiler only has the type of functor, the type generally suffices to uniquely identify the functor's operator() method.
Consider the two following template instantiations:
std::for_each<class std::vector<int>::const_iterator, class Functor>(...)
and
std::for_each<class std::vector<int>::const_iterator, void(*)(int)>(...)
Because the 1st is customised for each type of function object, and because operator() is often defined inline, then the compiler may, at its discretion, choose to inline the call.
In the 2nd scenario, the compiler will instantiate the template once for all functions of the same signature, therefore, it cannot easily inline the call.
Now, smart compilers may be able to figure out which function to call at compile time, especially in scenarios like this:
std::for_each(v.begin(), v.end(), &foo);
and still inline the function by generating custom instantiations instead of the single generic one mentioned earlier.
I always thought that the operator ( ) call is just like function call at runtime. how does it differ from a normal function call?
My guess is not very much. For evidence of this, look at your compiler's assembly output for each. Assuming the same level of optimization, it's likely to be nearly identical. (With the additional detail that the this pointer will have to get passed.)
Why is it easier to inline the application operator than a normal function?
To quote the blurb you quoted:
For example, it is easier to inline the application operator of a class than to inline a function passed as a pointer to function.
I am not a compiler person, but I read this as: If the function is being called through a function pointer, it's a hard problem for the compiler to guess whether the address stored in that function pointer will ever change at runtime, therefore it's not safe to replace the call instruction with the body of the function; come to think of it, the body of the function itself wouldn't necessarily be known at compile time.
How are they faster than function call?
In many circumstances I'd expect you wouldn't notice any difference. But, given your quotation's argument that the compiler is free to do more inlining, this could produce better code locality and fewer branches. If the code is called frequently this would produce notable speedup.