I was working on a project of mine when I realized I had written this, which the Nim compiler declared as GC-unsafe:
type
StateKind = enum
stProcessing, stDone
State = ref object
case kind: StateKind
of stProcessing:
progress: int
of stDone:
discard
let doneState = State(kind: stDone) # can't be const since both ref and case object
proc main() =
var state: State
state = doneState # unsafe
I thought this must have been a solved problem, so I took a bit and remembered defaultSslContext from asynchttpclient and the fix for the same mistake I made now.
The fixed code looked a bit overkill, however.
var doneStateVal {.threadvar.}: State
template doneState*: State =
if doneStateVal.isNil:
doneStateVal = State(kind: stDone)
doneStateVal
My question is, is there a simpler way to write this, or am I missing the point completely and applying the wrong fix?
I have quite a bit of these doneState variables so for the moment I devised a template.
template defaultVar(name, value): untyped {.dirty.} =
var `name val` {.gensym, threadvar.}: type(value)
template `name`*: type(value) =
if `name val`.isNil:
`name val` = value
`name val`
Well in your example you can just remove the ref and use a non-threadvar.
But in general, there is currently no better solution. We had some attempts but they all encouraged racy code. The "new runtime" will significantly improve the situation here as then standard seqs and strings can be put into the shared heap.