I am struggling with something like the following:
type
MyVariant = object
case kind: bool
of true:
intValue: int
of false:
floatValue: float
proc getValue(variant: MyVariant): auto =
if variant.kind:
result = variant.intValue
else:
result = variant.floatValue
proc main =
var a = MyVariant(kind: false, floatValue: 5.3)
echo a.getValue() + 1.0
main()
In my case I don't want to do something like this:
proc main =
var a = MyVariant(kind: false, floatValue: 5.3)
if a.kind:
echo a.floatValue+ 1.0
else:
echo a.intValue + 1
Is this possible? How should I manage this?
You're running into a classic problem :-D
No, it is not possible. This is the "cost" that Object variants bring with them - You need to explicitly describe what should happen for every scenario the variant could be in.
There is no "dynamic" programming in that sense, the static type system won't allow it.
var a = MyVariant(kind: false, floatValue: 5.3)
let floatVal: float = case a.kind:
of true: a.intValue.float
of false: a.floatValue
else: raise newException(ValueError, "Unsupported") # Not useful here, but imagine you had a variant with 5 kinds and only 2 kinds here were supported
echo floatVal + 1.0
If that isn't an option, then you "usually" solve these by approaching your problem in a different way. For example by using inheritance and dynamic dispatch consistently (methods).
type NumVal = ref object of Rootobj
type IntVal = ref object of NumVal
num: int
type FloatVal = ref object of NumVal
num: float
method printNum(self: NumVal) = echo "No Number"
method printNum(self: IntVal) = echo self.num + 1
method printNum(self: FloatVal) = echo self.num + 1.0
let x: NumVal = IntVal(num: 5)
let y: NumVal = FloatVal(num: 5.0)
x.printNum()
y.printNum()
If the return type is the same for all variants, I have a macro for this error, scroll to the bottom for a minimal example: https://github.com/mratsim/trace-of-radiance/blob/master/trace_of_radiance/support/emulate_classes_with_ADTs.nim
If the return type is not the same you need to pass it as an argument and it cannot be dynamic.
If you turn your variant variable into a const, you could get close to what you want using a template for the math operator. But this is probably not what you really want.:
type
MyVariant = object
case kind: bool
of true:
intValue: int
of false:
floatValue: float
template `+`*(lhs: MyVariant, rhs: untyped): untyped =
when lhs.kind:
lhs.intValue + rhs
else:
lhs.floatValue + rhs
proc main =
const a = MyVariant(kind: false, floatValue: 5.3)
echo a + 1.0
main()