They allow rewriting a field access or field assignment call to the `Action`
type to something else, there is more detail in the manual:
[https://nim-lang.org/docs/manual_experimental.html#special-operators-dot-operators](https://nim-lang.org/docs/manual_experimental.html#special-operators-dot-operators).
In the example I'm using the template to instead access a properties json field
and make those access/assignments feel seamless.
There is a remaining issue that the type returned is a `JsonNode` so in
practice you would need:
a.new_name.getStr() # extract the string from the JsonNode
a.algo.getInt() # extract the int from the JsonNode
Run
If you want truly seamless calls without the need of `getStr` you would need
something like the following, note the doAssert on the return type to make sure
we don't get JsonNodes, and we don't need the . experimental template either:
import json
type
Action = ref object
properties: JsonNode
template addPseudoField(A: typedesc, field: untyped, T: typedesc) =
# A is for the type namespace (Action)
template getType(args: varargs[untyped]): untyped =
# Alias the JsonNode getType function
when T is string:
getStr(args)
elif T is int:
getInt(args)
elif T is bool:
getBool(args)
elif T is float:
getFloat(args)
else:
# You can add your own type special marshaller/deserializer
raise newException(ValueError, "Unsupported type: " & $T)
proc `field`*(a: A): T =
a.properties[astToStr(field)].getType()
proc `field=`*(a: A, val: T) =
a.properties[astToStr(field)] = %val
Action.addPseudoField(layer, int)
Action.addPseudoField(add, bool)
Action.addPseudoField(vis, bool)
Action.addPseudoField(new_name, string)
Action.addPseudoField(algo, int)
var a = Action(
properties: %*{
"layer": 0,
"add": true,
"vis": false,
"new_name": "fancy_name"
}
)
echo a.new_name # "fancy_name"
a.algo = 10
echo a.algo # 10
doAssert a.algo is int
doAssert a.new_name is string
Run