Below is a way to access tuple and object fields by name. Something that would
be convenient from time to time. There was some posts on it before which lead
me to using fieldPairs. I tried applying generics to make it more "universal".
Aside from the efficiency issue of iterating through the fields each time, is
there a reason this should not be used?
type FieldTypeError* = object of FieldDefect
proc setField*[S:tuple|object; T](tp:var S; fld:string; val:T) =
for k,v in tp.fieldPairs:
when (typeOf(T) is typeOf(v)):
if k == fld:
v = val
return
raise newException(FieldTypeError, "A field named " & fld & " of type " &
$typeOf(val) & " not found")
proc setField*[S:ref tuple|ref object; T](tp:var S; fld:string; val:T) =
tp[].setField(fld, val)
proc getField*[S:tuple|object; T](tp:S; fld:string; def:typedesc[T]):T =
for k,v in tp.fieldPairs:
when (typeOf(T) is typeOf(v)):
if k == fld:
return v
raise newException(FieldTypeError, "A field named " & fld & " of type " &
$typeOf(def) & " not found")
proc getField*[S:ref tuple|ref object; T](tp:S; fld:string;
def:typedesc[T]):T =
tp[].getField(fld, def)
when isMainModule:
type
TPerson = tuple[name:string, num:int, tf:bool]
OPerson = object
name:string
num:int
tf:bool
RPerson = ref OPerson
var p1:TPerson = (name:"Alpha", num:0, tf:false)
doAssert p1 == (name: "Alpha", num: 0, tf: false)
p1.setField("name", "Beta")
doAssert p1 == (name: "Beta", num: 0, tf: false)
p1.setField("num", 1)
doAssert p1 == (name: "Beta", num: 1, tf: false)
p1.setField("tf", true)
doAssert p1 == (name: "Beta", num: 1, tf: true)
try:
p1.setField("nothing", "Nothing")
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected - No field named "nothing"
try:
p1.setField("name", 42)
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected - "name" should be string, not int
var p2 = OPerson(name:"Charlie", num:2)
doAssert $p2 == """(name: "Charlie", num: 2, tf: false)"""
p2.setField("name", "Delta")
doAssert $p2 == """(name: "Delta", num: 2, tf: false)"""
p2.setField("num", 3)
doAssert $p2 == """(name: "Delta", num: 3, tf: false)"""
p2.setField("tf", true)
doAssert $p2 == """(name: "Delta", num: 3, tf: true)"""
try:
p2.setField("nothing", "Nothing")
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected - No field named "nothing"
try:
p2.setField("name", 42)
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected
var p3 = new RPerson
p3.name = "Echo"
p3.num = 4
doAssert $p3[] == """(name: "Echo", num: 4, tf: false)"""
p3.setField("name", "Foxtrot")
doAssert $p3[] == """(name: "Foxtrot", num: 4, tf: false)"""
p3.setField("num", 5)
doAssert $p3[] == """(name: "Foxtrot", num: 5, tf: false)"""
p3.setField("tf", true)
doAssert $p3[] == """(name: "Foxtrot", num: 5, tf: true)"""
try:
p3.setField("nothing", "Nothing")
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected - No field named "nothing"
try:
p3.setField("name", 42)
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected
doAssert p1.getField("name",string) == "Beta"
doAssert p1.getField("num",int) == 1
doAssert p1.getField("tf",bool) == true
try:
doAssert p1.getField("nothing",string) == "Nothing"
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected
#doAssert p1.getField("wrong", string) == 5 # Compile error - Type
Mismatch
doAssert p2.getField("name",string) == "Delta"
doAssert p2.getField("num",int) == 3
doAssert p2.getField("tf",bool) == true
try:
doAssert p3.getField("nothing",int) == 42
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected
#doAssert p3.getField("wrong",int) == false # Compile error - Type
Mismatch
doAssert p3.getField("name",string) == "Foxtrot"
doAssert p3.getField("num",int) == 5
doAssert p3.getField("tf",bool) == true
try:
doAssert p3.getField("nothing",bool) == false
echo "Should have raised FieldTypeError"
except FieldTypeError:
discard # This is expected
#doAssert p3.getField("wrong",bool) == "false" # Compile error - Type
Mismatch
Run