It sounds reasonable that the discriminator of an object variant should be kept invariable to keep the object's data structure safe; I found, however, some scenarios in which it can be done. One way was to use the compiler directive --fieldChecks:off. I also attempted the same, but using the pragma {.fieldChecks: off.} and it worked. In fact I just found about that pragma by intuition, as it's not documented anywhere as far as I could research. I learnt also that you can use the pragma {.fieldChecks: on.} to bring back checking after the "unsafe" procedures are declared. I assume that "unsafe" procedures are all those that may use the discriminator once it has been changed.
For example, in the code below, type MyKind = enum mk1, mk2 MyObj = object case mk: MyKind: of mk1: x, y, z: float of mk2: u, v, w: float proc myProc(mk: MyKind; i, j, k: float): MyObj = case mk: of mk1: return MyObj(mk: mk1, x: i, y: j, z: k) of mk2: return MyObj(mk: mk2, u: i, v: j, w: k) {.fieldChecks: off.} # disable field checks for object variants proc change(mo: var MyObj; mkTo: MyKind) = # this is an unsafe proc that changes the discriminator # so the fieldChecks must me turned off to avoid runtime errors mo.mk = mkTo {.fieldChecks: on.} # turn field checks back on {.fieldChecks: off.} # disable field checks again, this proc `$` seems to fail at runtime otherwise proc `$`(mo: MyObj): string = # seemingly because of the previous proc, `$` also needs fieldChecks off # this can be made public* as it is safe to use result = "[mk: " & $mo.mk & "]:(" case mo.mk: of mk1: result &= "x:" & $mo.x & ", y:" & $mo.y & ", z:" & $mo.z of mk2: result &= "u:" & $mo.x & ", v:" & $mo.y & ", w:" & $mo.z result &= ")" {.fieldChecks: on.} # turn field checks back on proc rotate(mo: var MyObj) = # rotates the contents of mo regardless of what kind it is # this proc seems not to require fieldChecks turned off var temp: float orik: MyKind = mo.mk # this is the original kind change(mo, mk1) # temporary kind change # all kinds are treated as mk1, so less code is required temp = mo.x mo.x = mo.y mo.y = mo.z mo.z = temp change(mo, orik) # kind back to the original kind var p, q: MyObj p = myProc(mk1, 1, 2, 3) # p starts as kind "mk1" echo "p = ", p # output: p = [mk: mk1](x:1.0, y:2.0, z:3.0) change(p, mk2) # p is changed to kind "mk2" echo "p = ", p # output: p = [mk: mk2](u:1.0, v:2.0, w:3.0) rotate(p) # parameters of P are rotated echo "p = ", p # output: p = [mk: mk2](u:1.0, v:2.0, w:3.0) q = myProc(mk2, 4, 5, 6) # q starts as kind "mk2" echo "q = ", q # output: q = [mk: mk2](u:4.0, v:5.0, w:6.0) rotate(q) # parameters of q are rotated echo "q = ", q # output: q = [mk: mk2](u:5.0, v:6.0, w:4.0) Run