Let's say I want to declare a seq of ref objects (which I'm about to fill in the next few lines of code - so, we know the array will be filled).
However, if I do it like this, the array is unnecessarily initialized and zeroMem/memset:
var myArr: seq[someRefObject]
# doSth
myArr = someArr
I've tried using .noInit., but for some reason which I don't really understand things start ... breaking.
The question is: how would I go about safely declaring a variable like this (or a Table/string variable for that matter), that will be filled later, but without having it first auto-initialized?
My problem with this is:
Only available for numbers types.
So, I'm wondering what the safest solution would be in my case...
The issue with ref objects is that destructors assume an uninitialized ref is set to 0.
The =copy and =move procs will have a logic similar to:
proc `=`(dst: var MyObj, src: MyObj) =
# Nim refcounting starts at 0
if not dst.isNil:
if dst.refcount == 0:
destroy(dst)
else:
dst.refcount -= 1
dst.ptrAddr = src.ptrAddr
src.refcount += 1 # Assuming not optimized away
Let's say you get an unitialized ref (refcount: 0, ptrAddr: 0xFFFF), you'll try to destroy what is at 0xFFFF.
So uninitialized seq only makes sense for plain old data / trivial types.
Possibly of interest is newSeqNoInit at the end of https://github.com/c-blake/cligen/blob/master/cligen/sysUt.nim
My use case was wanting to do it for seq[bool] in https://github.com/c-blake/gralg which was annoyingly not included in SomeNumber, but is very much plain old data / trivial.
I don't know if it would help @drkameleon, but I think there is a strong argument to be made that the generic constraint for newSeqUninitialized[T] should be at least SomeOrdinal|SomeFloat instead of SomeNumber.
Thanks a lot for the answer and the explanation!
Extremely helpful and thorough as usual! :)
Yea it likely could be relaxed to something like
import std/typetraits
type StackType* = concept type ST
supportsCopyMem(ST)
Both newSeq and newSeqUninitialized produce the same seq and the same asm code . They both call newSeqPayload which calls alignedAlloc0.
Should a initialize parameter be added to newSeqPayload ?
these prevent writing code that is possible to write efficiently in other languages.
No, these only mean that you need to use a custom seq. But I agree it's not ideal.
No, these only mean that you need to use a custom seq. But I agree it's not ideal.
all other idiomatic nim code uses a seq -> one would have to copy from custom seq to seq -> defeats the purpose of avoiding zero:ing.