1\. This is the result of copying from `arr` to `result`, not the actual return
(`return x` does an implicit `result = x`). The following code avoids it:
proc foo(): seq[int] =
result = @[1, 2, 3]
echo cast[int](result[0].addr)
var arr = foo()
echo cast[int](arr[0].addr)
You can also avoid copying by using `let` instead of `var` (the copying is done
to avoid aliasing). Passing a value to a procedure will also not copy it.
2\. There is a `shallowCopy` that avoids the copying. Note that `shallowCopy`
is unsafe when the target is a global variable or managed heap location and the
source is a constant. You can avoid the unsafety via using a version where the
right-hand side must be mutable, e.g.:
proc `<-`[T](lhs: var T, rhs: var T) {.noSideEffect, magic: "ShallowCopy".}
3\. If throughput is your concern, then manual memory management won't help you
much per se. The primary cost of the the GC in Nim is the
allocation/deallocation overhead (plus the write barrier, but you incur that
only if you write a reference to a heap location or global variable), and you
incur that in C/C++ also, unless you use custom allocation schemes. I know that
Araq is also working on a region-based collector, which might alleviate the
overhead (enabled via `--gc:stack`, not sure how mature it is). Note that RAII
in particular may not help you much; reference counting as in `std::shared_ptr`
has overhead than Nim's GC, and something like `std::unique_ptr` is either not
memory-safe or incurs significant overhead (C++ chose the memory-unsafe
option). In order to have memory-safe move semantics without overhead, you need
linear or affine types, which would be a significant increase in language
complexity.