Thanks for your feedback! In hindsight it makes perfect sense that the provided 
string has to be known at compile time. I think that does not pose a problem 
for my use case.

My question came up while trying to understand metaprogramming and macros 
better. In my example above I'm not so much interested in an assignment 
statement per se but rather if I could do it with other functions. Assignment 
was just my first test.

I'll give you some context on what I'm trying to achieve. Sorry it's kinda 
lenghty, feel free to skip over the next three code snippets, if you are in a 
hurry or not interested in the details.

Currently, I'm experimenting with a tweening library. (Tweening basically means 
transitioning values smoothly over a given duration.) I've got it working so 
far but now I'm testing macros to create a nicer API. Essentially, I want to 
implement a function that takes a ref object, a sequence of keys and a sequence 
of target values.

I managed to get it working for floats quite nicely, with a syntax close to the 
example below (inspired by the `with` function in Kotlin and the Nim macro by 
Github user zevy). Given a ref object with keys `x, y: float`, I've come up 
with a syntax close to this
    
    
    tween(ent, duration = 0.5):
      x >>> 0.5
      y >>> 3.5
    
    
    Run

Here my custom `>>>` operator translates to a function that does the actual 
tweening, but for simplicity's sake, you can just think of an assignment that 
does a little bit extra (logging could be an example).

Next, I also want to support transitioning to other objects without having to 
implement custom functions for each type of object. For instance I want do do:
    
    
    tween(ent, duration = 0.5):
      pos >>> Vector2(x: 0.5, y: 3.5)
    
    
    Run

Here the key `pos` is also a `Vector2` and this code is a more concise version 
of something like this.
    
    
    tween(ent, duration = 0.5):
      pos.x >>> 0.5
      pos.y >>> 3.5
    
    
    Run

Coming back to my original question now. I've been looking at a way to access 
the keys of an object and transfer their values to another object (be it by 
plain assignment or another function). I had indeed looked at `fieldPairs` but 
only the one argument version. After Araq pointed it out, I looked again if I 
was missing anything. As it turns out, the two argument version of `fieldPairs` 
is sort of what I was trying to do (the calling syntax of the function in next 
example mirrors ES6 `Object.assign`):
    
    
    proc assign[T, S](dst: var T, src: S) =
      for name, v1, v2 in fieldPairs(src, dst):
        v2 = v1
    
    
    Run

Instead of `v2 = v1` I could theoretically plug in another function (e.g. a 
function that changes values gradually over time). But `fieldPairs` only works 
for tuples and (non ref) objects. With my `set` macro above from my first post 
however, I could also do it for ref objects like so:
    
    
    import macros
    
    # copied from above, modified as suggested by doofenstein
    macro set(ent: ref object | object, field: static[string], value: untyped): 
untyped =
      var dotExpr = newNimNode(nnkDotExpr)
      dotExpr.add(ent)
      dotExpr.add(newIdentNode(field))
      newAssignment(dotExpr, value)
    
    proc assign[S](dst: ref object, src: S) =
      for key, val in src.fieldPairs:
        set(dst, key, val)
    
    
    Run

So after some thinking and more studying I guess my question is why 
`fieldPairs` only works for tuples and plain objects. Was this a deliberate 
choice because of potential pitfalls that I am not seeing at the moment? And 
additionally: is there a more idiomatic way to achieve what I am doing in the 
last example?

Reply via email to