You can also create a variant object:
type
Person = object
name: string
age: Natural
MyValueKind = enum
mvkNumber
mvkString
mvkPerson
MyValue = object
case kind: MyValueKind
of mvkNumber:
numberVal: float
of mvkString:
stringVal: string
of mvkPerson:
personVal: Person
var tab: Table[string, MyValue]
tab["a"] = MyValue(kind: mvkNumber, numberVal: 42)
tab["jake"] = ΜyValue(kind: mvkPerson, personVal: Person(name: "Jake", age: 21))
Yes, this is indeed the right solution to simulate mixed types in a table.
But it works only for the table values. Variant objects are not allowed for the keys. I just tried and it failed with a strange message about the parallel 'fields' iterator not working for 'case' objects.
That is because the key of a table needs to be hashed. The generic hashing proc of the stdlib tries to hash the user type using fieldPairs. Unfortunately, that isn't supported for variant objects, hence the error.
Out of context the error message isn't the best, I agree.
You can always create a custom hash function for your object variant :) But you'll also need a custom equality function, so something like:
type
Person = object
name: string
age: Natural
MyValueKind = enum
mvkNumber
mvkString
mvkPerson
MyValue = object
case kind: MyValueKind
of mvkNumber:
numberVal: float
of mvkString:
stringVal: string
of mvkPerson:
personVal: Person
import tables, hashes
proc hash(x: Person): Hash =
result = result !& hash x.name
result = result !& hash x.age
result = !$result
proc hash(x: MyValue): Hash =
result = 0
case x.kind
of mvkNumber:
result = result !& hash x.numberVal
of mvkString:
result = result !& hash x.stringVal
of mvkPerson:
result = result !& hash x.personVal
result = !$result
proc `==`(a, b: MyValue): bool =
if a.kind != b.kind:
result = false
else:
case a.kind
of mvkNumber:
result = a.numberVal == b.numberVal
of mvkString:
result = a.stringVal == b.stringVal
of mvkPerson:
result = a.personVal == b.personVal
var tab = initTable[MyValue, MyValue]()
tab[MyValue(kind: mvkString, stringVal: "a")] = MyValue(kind: mvkNumber, numberVal: 42)
tab[MyValue(kind: mvkNumber, numberVal: 42.0)] = MyValue(kind: mvkPerson, personVal: Person(name: "Jake", age: 21))
echo tab
I think there are libraries in Nimble which allow to reduce the boilerplate here, or you can always make some macros :P
Of course, I created a hash function, but nevertheless it failed.
Looking at your example, which works, the only difference is that I didn’t defined the == proc.
Now, I understand the error message I got. For an object without variant fields, the compiler translates a comparison as a loop on each field using a field iterator. But this doesn’t work for objects with variant fields as explained by the message.
I think this is a limitation that could be removed in the future. As far as I remember, Ada is able to compare records with variants (at least, I’m pretty sure it was the case for the Alsys compiler I used). Now, this is certainly not something we do frequently.