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

Reply via email to