I'm trying to simplify my program syntax by creating nice aliases. Cannot understand what's wrong when returning var t where t is typedesc:
import tables
proc getTableOf*(t: typedesc): ref Table[int, t] =
var table {.global.} = newTable[int, t]()
return table
proc getVal(key: int, t: typedesc): t = # just an easy accessor (alias)
getTableOf(t)[key]
# check they are the same
getTableOf(bool)[0] = false
assert 0.getVal(bool) == getTableOf(bool)[0] # for key "0", lookup value in boolean table - this works
echo "ok"
proc getMutableVal(key: int, t: typedesc): var t =
getTableOf(t)[key]
getTableOf(bool)[0] = false # get boolean table, select mutable value by key - this works!
0.getMutableVal(bool) = false # same: for key "0", get mutable value from boolean table
# ^-- Error: type mismatch: got <bool> but expected 'None'
assert 0.getVal(bool) == false
echo "ok"
Please help! :/
I don't know how to make it work with : var t, maybe a bug or not supported; works with template getMutableVal(key: int, t: typedesc): var typed =.
I assume you need 0.getMutableVal(bool) = false syntax, otherwise you can pass types as a generic parameter (proc getMutableVal[t]...), that works with : var t.
Thanks a lot LeuGim!! The template returning var typed works like a charm!
Still, does anyone know what's wrong with that proc? And why should I ever use proc(T: typedesc) instead of template(T: typedesc)?
proc getMutableVal(key: int, t: typedesc): var t = # <-- fail
getTableOf(t)[key]
template getMutableVal(key: int, t: typedesc): var typed = # <-- fine
getTableOf(t)[key]
You need to use generics.
import tables
proc getTableOf*[T]: ref Table[int, T] =
var table {.global.} = newTable[int, T]()
return table
proc getVal[T](key: int): T =
getTableOf[T]()[key]
getTableOf[bool]()[0] = true
assert getVal[bool](0) == getTableOf[bool]()[0]
assert getVal[bool](0)
proc getMutableVal[T](key: int): var T =
getTableOf[T]()[key]
getTableOf[bool]()[0] = true
assert getVal[bool](0)
getMutableVal[bool](0) = false
assert(not getVal[bool](0))
If you still want to pass a typedesc as an argument, you can use typedesc[T].
import tables
proc getTableOf*[T](desc: typedesc[T]): ref Table[int, T] =
var table {.global.} = newTable[int, T]()
return table
proc getVal[T](key: int, desc: typedesc[T]): T =
getTableOf(T)[key]
getTableOf(bool)[0] = true
assert 0.getVal(bool) == getTableOf(bool)[0]
assert 0.getVal(bool)
proc getMutableVal[T](key: int, desc: typedesc[T]): var T =
getTableOf(T)[key]
getTableOf(bool)[0] = true
assert 0.getVal(bool)
0.getMutableVal(bool) = false
assert(not getVal(0, bool))
Keep in mind you can also turn getVal and getMutableVal into templates instead of procs to get rid of runtime overhead. Templates don't need type information, they transform AST into other AST during compile time (from my knowledge at least).
Keep in mind you can also turn getVal and getMutableVal into templates instead of procs to get rid of runtime overhead. Templates don't need type information, they transform AST into other AST during compile time (from my knowledge at least).
Yes templates always inline at the Nim level. But if a proc is enough and you don't want the function call overhead, just add the {.inline.} pragma and keep your templates in reserve for things that require them.
I've done an in-depth review of the C code and Assembly produced of inline procs vs templates. C code is different, assembly is the same.
Thank you guys! I stayed with templates, don't know why I didn't use them from the beginning.
But typedesc[T] is really, really evil and black magic:
proc getMutableVal[T](key: int, desc: typedesc[T]): var T =
getTableOf(T)[key]