Here's a workaround, that only works if the tuple is un-named:
proc test[T](tup:T)=
for name, val in tup.fieldPairs:
const index = name["Field".len .. ^1].parseInt
const val2 = tup[index] # this works
test((1,2)) #works
test((foo:1,bar:2)) #doesn't work
proc test[T](t:T)=
for index, name in T.fieldsIndexed:
# index, name are known at CT, and this works as if for loop was unrolled (just like for fieldPairs)
let val = t[index]
test((1,2))
for ki,ai,bi in fieldPairs((bar11:1, bar12:2),(bar21:3, bar22:4)) # doesn't work: field names differ
for ki,ai,bi in fieldPairs((1,2), (3.0, "foo") ) # doesn't work: field names same but types differ
fieldPairs could be replaced advantageously by fieldsIndexed, lift those restrictions, and allow much more flexibility:
proc testMulti[T1, T2](t1:T1, t2:T2)=
for index, name in T1.fieldsIndexed:
let val1 = t1[index]
let val2 = t2[index]
testMulti((1,2), (bar:3.0, baz:"foo") ) # would work
proc doInit[T]():auto=
var a: T
return a
proc test[T]()=
const tup=doInit[T]()
for ai in tup.fields:
# BUG! see https://github.com/nim-lang/Nim/issues/7590
test[(1,2).type]()
with fieldsIndexed, it would work out of the box, bypassing https://github.com/nim-lang/Nim/issues/7590 Even if that bug were fixed, it's wasteful to have to create an instance in const tup=doInit[T]() just to get its fields
is there a way (at compile time) to get field name given type + (compile time) index? if yes, we only need:
for index in T.fieldsIndexedSingle:
const name = T.magicNames(i) # not sure what that would be though
let val = t[index]
instead of: for index, name in T.fieldsIndexed:
I think we need something more generic, otherwise we end up introducing indexing version of every other iterator. Something like indexed iterator that accepts another iterator as argument.
Even if it is not possible now, patch Nim compiler to make it possible.
@cdome @mratsim we're talking about different things here. I'm talking about loop-unrollled for loop, where index index is known at compile time:
for index, name in T.fieldsIndexed:
body
#unrolls to:
block:
const index=0
const name=T_field_0 # ie, 1st field of T
body
block:
const index=1
const name=T_field_1
body
#etc
const n=10 # or whatever compile time known int
for index in n.rangeCT:
body
#unrolls to:
block:
const index=0
body
block:
const index=0
body
#etc
which could be used as:
#using len and fieldNames from https://github.com/nim-lang/Nim/pull/7597
proc test[T](t:T):
const names= fieldNames[T]()
for index in T.len.rangeCT:
static: echo index # index known at CT
echo (index, names[index], t[index])
it's less convenient when iterating over fields of an object/tuple, but more generally applicable (only needs a compile time integer n)