Here's an extract of my code. My issue is with the `proc `$`(s: SNodeAny): string =` function.
Basically, it is just a long list of `if` statements (could be a `case` as well, doesn't matter) to check if the object is of some type, and then apply the `$` operator on the casted type. I feel this could be replaced by a two line macro or template, but for this I need to be able to deduce the original type of the passed SNode before I can cast and apply the `$` operator. My real code now includes 4 of these kind of functions where I need to check for every possible node kind, cast it, and apply some kind of generic function to it. import strutils type IPv4Address = distinct string IPv6Address = distinct string MacAddress = distinct string Interval = distinct float # ... many more distinct types type SNodeAny = ref object of Rootobj id: string parent: SNodeAny SNodeGroup = ref object of SNodeAny children: seq[SNodeAny] SNodeParam = ref object of SNodeAny SNode[T] = ref object of SNodeParam val: T proc newSNode[T](id: string, val: T): SNodeAny = SNode[T](id: id, val: val).SNodeAny proc newSNodeGroup(id: string, children: openarray[SNodeAny]): SNodeAny = var s = SNodeGroup(id: id) for c in children.items: s.children.add c c.parent = result return s proc `$`(v: IPv4Address): string = v.string proc `$`(v: IPv6Address): string = v.string proc `$`(v: MacAddress): string = v.string proc `$`(v: Interval): string = $ v.float proc `$`(s: SNodeAny): string = if s of SNode[bool]: result = $ s.SNode[:bool].val if s of SNode[int]: result = $ s.SNode[:int].val if s of SNode[IPv4Address]: result = $ s.SNode[:IPv4Address].val if s of SNode[IPv6Address]: result = $ s.SNode[:IPv6Address].val if s of SNode[MacAddress]: result = $ s.SNode[:MacAddress].val if s of SNode[Interval]: result = $ s.SNode[:Interval].val # many more of those proc dump(s: SNodeAny, depth: int = 0) = var l = repeat(" ", depth) l.add s.id if s of SNodeParam: l.add "=" & $ s echo l if s of SNodeGroup: for c in s.SNodeGroup.children.items: dump(c, depth+1) var s = newSNodeGroup("system", [ newSNodeGroup("identification", [ newSNode("name", "device 123"), newSNode("location", "rack J2"), newSNode("weight", 42.1), newSNode("enabled", true), newSNode("address", IPv4Address("10.0.0.3")), ]) ]) s.dump Run