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

Reply via email to