On Mon, Jun 8, 2020 at 8:20 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
On 6/7/2020 11:14 PM, Manu wrote:
> I think a first part of the conversation to understand, is that since D doesn't
> really have first-class `inline` (just a pragma, assumed to be low-level
> compiler control), I think most people bring their conceptual definition over
> from C/C++, and that definition is a little odd (although it is immensely
> useful), but it's not like what D does.

C/C++ inline has always been a hint to the compiler, not a command.

It's not a hint at all. It's a mechanical tool; it marks symbols with internal linkage, and it also doesn't emit them if it's never referenced.
The compiler may not choose to ignore that behaviour, it's absolutely necessary, and very important.

> In C/C++, inline says that a function will be emit to the binary only when it is
> called, and the function is marked with internal linkage (it is not visible to
> the linker from the symbol table)
> By this definition; what inline REALLY means is that the function is not placed
> in the binary where it is defined, it is placed in the binary where it is
> CALLED, and each CU that calls an inline function receives their own copy of the
> function.

Why does it matter where it is emitted? Why would you want multiple copies of
the same function in the binary?

I want zero copies if it's never called. That's very important.
I also want copies to appear locally when it is referenced; inline functions should NOT require that you link something to get the code... that's not inline at all.

> Another take on inline, and perhaps a more natural take (if your mind is not
> poisoned by other native languages), is that the function is not actually emit
> to an object anywhere, it is rather wired directly inline into the AST instead
> of 'called'. Essentially a form of AST macro.

The problem with this is what is inlined and what isn't is rather fluid, i.e. it
varies depending on circumstances and which compiler you use. For example, if
you recursively call a function, it's going to have to give up on inlining it.
Changes in the compiler can expand or contract inlining opportunities. Having it
inline or issue an error is disaster for compiling existing code without
constantly breaking it.

I understand why this particular take is more complicated; and as such I wouldn't suggest we do it. I'm just offering it as one possible take on the concept.
I think to make this form work, it must be handled in the frontend; essentially an AST macro. Naturally, it would fail on recursive calls, because that would be a recursive expansion.
I'm not suggesting we do this, except maybe what I describe as the #3 use case could potentially be this.

> I reach for inline in C/C++ for various different reasons at different times,
> and I'd like it if we were able to express each of them:
>
> 1. I only want the function to be present in the CALLING binary. I do not want
> an inline function present in the local binary where it was defined (unless it
> was called internally). I do not want a linker to see the inline function
> symbols and be able to link to them externally. [This is about linkage and
> controlling the binary or distribution environment]

Why? What is the problem with the emission of one copy where it was defined?

That's the antithesis of inline. If I wanted that, I wouldn't mark it inline.
I don't want a binary full of code that shouldn't be there. It's very important to be able to control what code is in your binaries.

If it's not referenced, it doesn't exist.

> 2. I am unhappy that the optimiser chose to not inline a function call, and I
> want to override that judgement. [This is about micro-optimisation]

It's not always possible to inline a function.

Sure, but in this #2 case, I know it's possible, but the compiler chose not to. This #2 case is the 'hint' form.

> 3. I want to treat the function like an AST macro; I want the function inserted
> at the callsite, and I want to have total confidence in this mechanic. [This is
> about articulate mechanical control over code-gen; ie, I know necessary facts
> about the execution context/callstack that I expect to maintain]

The PR I have on this makes it an informational warning. You can choose to be
notified if inlining fails.

That's not sufficient though for all use cases. This is a different kind of inline (I think it's 'force inline').
This #3 mechanic is rare, and #1/2 are overwhelmingly common. You don't want a sea of warnings to apply to cases of 1/2.
I think it's important to be able to distinguish #3 from the other 2 cases.

> Are there non-theoretical use cases I've missed that people have encountered?

At its root, inlining is an optimization, like deciding which variables go into
registers.

No, actually... it's not. It's not an 'optimisation' in any case except maaaaybe #2; it's about control of the binary output and code generation.
Low level control of code generation is important in native languages; that's why we're here.