@mratsim's comment in this thread led me to look up the {.shallow.} pragma. But I'm a bit confused by the description in the manual:
The shallow pragma affects the semantics of a type: The compiler is allowed to make a shallow copy. This can cause serious semantic issues and break memory safety! However, it can speed up assignments considerably, because the semantics of Nim require deep copying of sequences and strings.
First, I assume "copy" here means the normal copying of a value by assignment, parameter passing or results; not the copying done when sending objects between threads. (I ask because I already think of this copying as being shallow, since refs are not traversed. Yes, seq/strings are copied, but that's because they have value semantics.)
My best guess about the precise meaning of shallow is that it forces seq and string values embedded directly in the object to be shallow-copied, such that the copies point to the same heap buffers as the originals, but has no effect on other types. Correct?
If so, it leads me to wonder
Another thing just occurred to me: IIRC, both seq and string are implemented as (pointer, length) tuples. So if a shallow-copied instance's length is changed, then (a) the copy's length doesn't change though its buffer does, and (b) if the resize causes reallocation, the copy is now pointing to a freed heap block. Presumably this is what's meant by "break memory safety"?! A more direct warning would be good, like "you must not resize either copy or heap corruption may occur."