That document says that it “describes the upcoming Nim runtime which does not use classical GC algorithms anymore but is based on destructors and move semantics”.
Is that referring to arc/orc? It is a bit unclear to me because at some point there was something called the “new runtime” which I believe was abandoned and replace with arc and orc. So is that document accurate and does it refer to arc and orc?
And much more. Google helps, but not always. Nim manual doesn't give enough details.
If you have to ask, don't use .inheritable. An .inline proc is a proc that is inlined. If you have to ask, don't use it.
The Nim manual has enough details but it doesn't try to reinvent Wikipedia.
I can at least explain the {.inline.} pragma:
Say I have two Nim files:
# foo.nim
import bar
proc getNum*(): int =
add(10, 20)
# bar.nim
proc add*(a, b: int): int =
a + b
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);
}
// bar.c
NI add__bar_456(NI a, NI b) {
return a + b;
}
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
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);
}
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;
}
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 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`.
The different between inheriting from RootObj or RefRoot and from a base object, is the 2 object hierarchies that both inherit from one of the system define roots can interfere with each other. https://play.nim-lang.org/#ix=3UuD. In this example A and it's "siblings" may be the intended target, but B would work as well. Although this is far fetched, it is definitely possible.
On the difference between object and ref object is that object is a value type, but ref object is a reference type. This means that changes to a ref object are reflected across all of the same references. https://play.nim-lang.org/#ix=3UuF. This means that a reference type stores the memory address of the data with a non-ref type (regular object) store the actual data. This has an interesting application (as well as others):
Given that the {.inline.} pragma basically just passes the inline "hint" to the C/C++ compiler, which might or might not decide to actually inline the function, doesn't it make more sense to instead use a template, which will actually "embed" the template code into the call location?
If that is correct, why would you ever want to use {.inline.} rather than a native nim template? Or perhaps I misunderstood the way templates work?
Sure, I agree that if you can get things working with a procedure it is best to use that instead of a template. However, if you _really want to inline a procedure, it seems better to use a template, which will _ensure that the code is inlined, while the inline pragma will just _ask the C compiler to inline the procedure. The C compiler will then decide what to depending on some heuristic which might or might not take the online marker into account. My understanding is that most C compilers nowadays basically ignore inline markers and just do whatever they think it’s best (including inlining functions that are not marked as inline).
In a way this shows how nim can let you do thinks that are not possible (or very difficult or clunky) in C, despite the fact that it compiles down to C.
If you use a template as an inline function you need to be extra careful to avoid double evaluation of parameters. Also there are some situations like with var return parameters where in Nim it's impossible to replicate the exact behaviour of a (inlined) proc with a template until views are stabilised unless you use some serious pointer based workarounds.
In a way this shows how nim can let you do thinks that are not possible (or very difficult or clunky) in C, despite the fact that it compiles down to C.
In C you can use a macro for that or on gcc __attribute__((always_inline)). But with the first you get the same issue of parameter double evaluation.
In the end in both templates in Nim and macros in C both are pretty poor inline functions and better suited for things like reducing code duplication in some situations, etc.
In my experience, a proc tagged with {.inline.} is always inlined.
Nim doesn't tag it with C inline it also tags it with static which convey to the C compiler that only this specific compilation unit will ever call that proc. In that case, even large procs are inlined if they are called once.