proc f(t: seq[string]) = echo "f:", cast[int](t.addr) proc fv(t: var seq[string]) = echo "fv:", cast[int](t.addr) var t = @["foo", "bar"] echo "t:", cast[int](t.addr) f t fv t
t: 94578224415136 f:140724500006944 fv:94578224415136
Since non-var parameters cannot be modified the compiler is always free to
pass arguments by reference if it considers it can speed up execution.
But I saw this sentence from Nim Manual, which made me a little puzzled 🤔
seq s and strings are 2 pointer sizes so do not experience that optimization their value component is passed as copy, but since they own heap data that is not copied this can be seen below:
proc f(t: seq[string]) =
echo "f:", cast[int](t[0].addr)
proc fv(t: var seq[string]) =
echo "fv:", cast[int](t[0].addr)
var t = @["foo", "bar"]
echo "t:", cast[int](t[0].addr)
f t
fv t
type P = object
x, y: int
proc f(a: P) =
echo "f:", cast[int](a.addr)
var a = P(x: 1, y: 2)
echo "a: ", cast[int](a.addr)
f a
a: 93922143641920
f:140728652581696
for non-pointer types are also different memory addresses 🤔
As I mentioned, the compiler doesn't always optimize, but it does when the object is big enough:
type P = object
x, y: int64
type
P2 = object
x, y, z, d: int64
proc f[T](a: T) =
echo "f:", cast[int](a.addr)
var a = P(x: 1, y: 2)
echo "a: ", cast[int](a.addr)
f a
var b = P2(x: 1, y: 2, z: 3, d: 4)
echo "b: ", cast[int](b.addr)
f b
proc f(t: seq[string]) =
echo "f:", cast[int](t[0].addr)
proc fv(t: var seq[string]) =
echo "fv:", cast[int](t[0].addr)
var t = @["foo", "bar"]
echo "t:", cast[int](t[0].addr)
f t
fv t
Now all output is same .