I'm a bit confused about the best way to deal with this error. My code looks something like the following:
type
Kind = enum
kindA
kindB
kindC
MyObject = object
case kind: Kind
of kindA:
dataA: int
of kindB:
dataB: int
of kindC:
dataC1: int
dataC2: int
dataAll1: int
dataAll2: int
dataAll3: int
proc foo(): MyObject =
let kind = kindA
if kind == kindA:
result = MyObject(
kind: kind,
dataA: 1,
dataAll1: 10,
dataAll2: 20,
dataAll3: 30
)
elif kind == kindB:
result = MyObject(
kind: kind,
dataB: 2,
dataAll1: 10,
dataAll2: 20,
dataAll3: 30
)
else:
result = MyObject(
kind: kind,
dataC1: 3,
dataC2: 4,
dataAll1: 10,
dataAll2: 20,
dataAll3: 30
)
which fails with: you must provide a compile-time value for the discriminator 'kind' in order to prove that it's safe to initialize 'dataA'.
Interestingly, if I replace the if-else with a case statement, the code does compile; that's fine, I can use case if necessary. However this brings me to my next issue, which is that it does not feel very ergonomic to have to repeat the initialization of dataAll1-3 in each case despite having the same values.
One possible solution would be to extract dataAll1-3 into its own type (say a tuple) and initialize that separately, passing the same value in each case. Something like:
type
Kind = enum
kindA
kindB
kindC
MyObject = object
case kind: Kind
of kindA:
dataA: int
of kindB:
dataB: int
of kindC:
dataC1: int
dataC2: int
dataAll: tuple[data1, data2, data3: int]
proc foo(): MyObject =
let kind = kindA
let all = (10, 20, 30)
case kind
of kindA:
result = MyObject(
kind: kind,
dataA: 1,
dataAll: all
)
of kindB:
result = MyObject(
kind: kind,
dataB: 2,
dataAll: all
)
of kindC:
result = MyObject(
kind: kind,
dataC1: 3,
dataC2: 4,
dataAll: all
)
This works well enough in a simple case, but still doesn't feel very "good". The situation would be even worse if the three fields were not related (in which case it doesn't really make sense to group them together).
Does anyone have a more ergonomic way to solve this issue? Thanks!
var t = T(s: "hoi", kind: A, a: 13) echo t
Overloading a newT proc?
type TKind = enum
A, B
type T = object
s: string
case kind: TKind
of A:
a: int
of B:
b: string
# for TKind A
# assuming TKind A can be derived from fact that second
# parameter 'a: int'
proc newT(s: string, a: int): T =
T(s: s, kind: A, a: a)
# for TKind B
proc newT(s: string, b: string): T =
T(s: s, kind: B, b: b)
var
ta = T(s: "hoi", kind: A, a: 123)
tb = T(s: "bye", kind: B, b: "yippie")
echo "ta = ", ta
echo "tb = ", tb
echo "-----"
ta = newT("hoi again", 456)
tb = newT("bye again", "oops")
echo "ta = ", ta
echo "tb = ", tb
Whats wrong with initializing common fields independently?
proc foo(): MyObject =
let kind = kindA
result = case kind:
of kindA: MyObject(kind: kind, dataA: 1)
of kindB: MyObject(kind: kind, dataB: 2)
of kindC: MyObject(kind: kind, dataC1: 3, dataC2: 4)
result.dataAll1 = 10
result.dataAll2 = 20
result.dataAll3 = 30