user53754: A friend has told me I shouldn't rely on functions because, during execution, they occupy a significant amount of RAM.
Is that true or, if it isn't, what's the maximum suggested level of function nesting at runtime?

user4143: 
A friend has told me I shouldn't rely on functions because, during execution, they occupy a significant amount of RAM.

I wouldn't say "significant", but some RAM is used, yes.
Every time a function is called any registers used in the execution of that function are placed onto the stack. Also some parameters to the function may be passed on the stack (depending on the ABI for the architecture you're using). Further, any local variables used inside the function also go on the stack.
These are only temporary allocations and are released again when the function exits.
Depending on your program the "call stack" can be insignificant compared to the local variables.

what's the maximum suggested level of function nesting at runtime?

Low enough that you don't run out of memory. When you have plenty of memory then your call stack is irrelevant. When you only have a couple of hundred bytes, or a hardware stack (like on the low-end PIC microcontrollers) with a limited depth, then keeping your program flatter can be better.
The main reason for flattening a program is usually for execution speed rather than for memory use.

user7508: I guess avoiding functions may have been relevant with dumb compilers, a
few decades ago. Compilers today are pretty good at optimizing and,
since recently, the Arduino environment enables “link time
optimization”. This means the optimizer can see the whole program at
once, which enables:

function inlining across compilation units (and the optimizer does
this pretty aggressively)
saving, in the function prologue, only the registers that really need
to be saved.

In most cases, the “optimal” size for a function is whatever size
optimizes the readability of the code. In the rare cases where you would
need to merge a function into its callers for performance purposes, you
can qualify the function as
inline __attribute__((always_inline))

But this only makes sense after you disassembled the program and noticed the
compiler did not make the right optimization choices. A quite infrequent
situation.

53754: <p>A friend has told me I shouldn't rely on functions because, during execution, they occupy a significant amount of RAM.</p>
<p>Is that true or, if it isn't, what's the maximum suggested level of function nesting at runtime?</p>
 4143: <blockquote>
<p>A friend has told me I shouldn't rely on functions because, during execution, they occupy a significant amount of RAM.</p>
</blockquote>
<p>I wouldn't say &quot;significant&quot;, but <em>some</em> RAM is used, yes.</p>
<p>Every time a function is called any registers used in the execution of that function are placed onto the stack. Also some parameters to the function may be passed on the stack (depending on the ABI for the architecture you're using). Further, any local variables used inside the function also go on the stack.</p>
<p>These are only temporary allocations and are released again when the function exits.</p>
<p>Depending on your program the &quot;call stack&quot; can be insignificant compared to the local variables.</p>
<blockquote>
<p>what's the maximum suggested level of function nesting at runtime?</p>
</blockquote>
<p>Low enough that you don't run out of memory. When you have plenty of memory then your call stack is irrelevant. When you only have a couple of hundred bytes, or a hardware stack (like on the low-end PIC microcontrollers) with a limited depth, then keeping your program flatter can be better.</p>
<p>The main reason for flattening a program is usually for execution speed rather than for memory use.</p>
 7508: <p>I guess avoiding functions may have been relevant with dumb compilers, a
few decades ago. Compilers today are pretty good at optimizing and,
since recently, the Arduino environment enables “link time
optimization”. This means the optimizer can see the whole program at
once, which enables:</p>
<ul>
<li>function inlining across compilation units (and the optimizer does
this pretty aggressively)</li>
<li>saving, in the function prologue, only the registers that really need
to be saved.</li>
</ul>
<p>In most cases, the “optimal” size for a function is whatever size
optimizes the readability of the code. In the rare cases where you would
need to merge a function into its callers for performance purposes, you
can qualify the function as</p>
<pre class="lang-cpp prettyprint-override"><code>inline __attribute__((always_inline))
</code></pre>
<p>But this only makes sense after you disassembled the program and noticed the
compiler did not make the right optimization choices. A quite infrequent
situation.</p>
