Does anyone have a sense of how shallow sequence copies interact with the GC? What about {.shallow.} objects containing sequences?
I'd like to allocate a buffer, store pointers to it for a while in an unpredictable (but cycle-free) way, then have the garbage collector free it at some point after it becomes unreachable. Is there a simple way to do this without writing my own reference-counting system?
Memory safety with 'shallow' in its various forms is only a problem when you interact with 'const' data which is not allocated on the GC'ed heap. Avoid that and it's all good.
I'll keep this in mind, but I haven't been declaring any const sequences and I've still been running into memory corruption/early freeing issues (I've only been using sequences returned from runtime function calls, like @ and newSeq).
You can use --d:useGcAssert and then you'll get some checking at runtime that what you do is sane.
This is good to know. Thanks.
You need to be more concrete.
Here's an example. The following seems to work just fine:
type SeqSlice {.shallow.} = object
buffer: seq[int]
proc asSeqSlice(s: seq[int]): SeqSlice =
result.buffer.shallowCopy s
(proc() =
var a = @[0, 1, 2].asSeqSlice
echo "a: ", a.buffer, " at ", cast[int](addr a.buffer[0])
)()
But if I move the var a ... and echo "a: " ... lines out of the procedure and into the global scope, I get the following runtime error:
[GCASSERT] incRef: interiorPtr
Traceback (most recent call last)
test.nim(7) test
test.nim(5) asSeqSlice
gc.nim(265) unsureAsgnRef
gc.nim(104) incRef
Error: execution of an external program failed
That's because the compiler got too smart and now creates a 'const' seq for @[0, 1, 2].
I had a feeling there was something like that going on. Sneaky Nim...
That said, it's bad style to hijack a sequence like this. Your SeqSlice should create its own seq that then has reference semantics.
That makes sense. Coming from D/NumPy/Julia, I'm used to being able to take slices and forget where they came from (unless I'm writing to them, of course), but I'm sure I'll get used to thinking in terms of seq sooner or later.
proc copyRef[T](theSeq: seq[T]): seq[T] =
shallowCopy(result, theSeq)
var a1 = @[0,1,2]
var a2 = a1.copyRef
echo "a2: ", a2, " at ", a2[0]
a2[0] = 255
echo a1 # [255, 1, 2]
echo a2 # [255, 1, 2]