I can at least explain the `{.inline.}` pragma:

Say I have two Nim files:
    
    
    # foo.nim
    import bar
    
    proc getNum*(): int =
      add(10, 20)
    
    
    Run
    
    
    # bar.nim
    
    proc add*(a, b: int): int =
      a + b
    
    
    Run

Each `.nim` file is compiled to a `.c` file, which might look something like 
this:
    
    
    // foo.c
    extern NI add__bar_456(NI a, NI b);
    
    NI getNum__foo_123(void) {
      return add__bar_456(10, 20);
    }
    
    
    Run
    
    
    // bar.c
    
    NI add__bar_456(NI a, NI b) {
      return a + b;
    }
    
    
    Run

The C compiler is then invoked for each `.c` file to compile it into a `.o` 
file. When compiling `foo.c` it does not know the contents of `bar.c`! This 
means the compiler cannot optimise `return add__bar_456(10, 20);` into `return 
10 + 20;`

Now if we annotate the `add` proc with `{.inline.}`:
    
    
    # bar.nim
    
    proc add*(a, b: int): int {.inline.} =
      a + b
    
    
    Run

The generated C function for `add` will appear separately in each file where 
it's used, annotated with the `inline` keyword in C, which is a suggestion for 
the C compiler to substitute its contents into the place where it's used 
(though as long as it can see the function it might do so anyways even without 
the keyword). So `foo.c` will now look like this:
    
    
    // foo.c
    static inline NI add__bar_456(NI a, NI b) {
      return a + b;
    }
    
    NI getNum__foo_123(void) {
      return add__bar_456(10, 20);
    }
    
    
    Run

Now the C compiler knows the implementation of `add__bar_456` when it's 
compiling `foo.c`, so it will hopefully inline it like so:
    
    
    NI getNum__foo_123(void) {
      return 10 + 20;
    }
    
    
    Run

In summary: `{.inline.}` is a pragma that causes a proc to be generated 
separately in each module where it's used, and annotated with C's `inline` 
keyword, in the hopes that the C compiler will do the actual inlining. There's 
nothing in the C standard that says the compiler 
_[will](https://forum.nim-lang.org/postActivity.xml#will) do this, but it ought 
to, if it deems it to be beneficial for performance, and assuming you compiled 
with `-d:release` or `-d:danger`.

Needless to say, apart from tiny functions like `add`, this will increase the 
size of your executable, because now the whole body of the function is copied 
into the place where it's used. But it saves the cost of a function call, so if 
applied to the right kinds of procs (e.g. maths functions, getters/setters and 
other small procs with frequent usage) it can be great for performance.

If you don't want to worry about this though, an alternative is to enable 
link-time optimisation with 
[`-d:lto`](https://nim-lang.org/faq.html#which-option-to-use-for-the-fastest-executable).
 

Reply via email to