Hello, what is the right way to forward varargs?
proc echoWrapper(args: varargs[string, `$`]) =
echo args
echoWrapper "hi", " bye"
Ok, how about a bit more useful case, that is forwarding varargs[expr]?
template forwarder(args: varargs[expr]) =
echo args
As far as I understand there has to be some expand magic, so echo would be rewritten as echo expand(args) I have found a method which should work in most of the cases.
macro appendVarargToCall(c: expr, e: expr): expr =
result = c
for a in e.children:
result.add(a)
template echoWrapper(args: varargs[expr]) =
appendVarargToCall(echo(), args)
What this does is expands varargs and appends the elements to the call node. So that's how we can forward varargs by inserting them in the end of the call. With liitle modification the macro can insert expanded varargs in arbitrary positions.
Just another witness of Nim's power!
proc p*(args: varargs[typed, `$`]) =
echo args
proc p*(args: varargs[typed, `$`]) =
echo args
I have never been able to make varargs[typed, `$`] work. I use string instead of typed:
proc p(args: varargs[string, `$`]) =
echo args
Unfortunately, args is displayed as an array and you have to loop on the elements and use stdout.write to get what is expected.
To forward a varargs, this works as the compiler transforms the sequence as a list of parameters:
proc p1(args: varargs[string]) =
echo args
proc p2(args: varargs[string, `$`]) =
p1(args)
p2(1, 2, 3)
Thus, adding an element can be done this way:
proc p1(args: varargs[string]) =
echo args
proc p2(args: varargs[string, `$`]) =
p1(@args & "4")
p2(1, 2, 3)
There is also a macro unpackVarargs but it is not documented.
Seems like unpack_varargs behaves not exactly as calling directly
import macros
proc p(args: varargs[string, `$`]) = unpack_varargs(echo, args)
p 1, 2, 3
echo 1, 2, 3
Produces
["1", "2", "3"]
123
Yeah that's what @lscrd meant about having to loop through with stdout.write, if you want to duplicate echo's behaviour
proc p1(args: varargs[string, `$`]) =
for a in args:
stdout.write(a)
stdout.write('\n')
proc p2(args: varargs[string, `$`]) =
p1(@args & "4")
p2(1, 2, 3) # 1234
Hey! Just to check, is there a good way unpack/forward varargs in a recent Nim version, like 2.2.0? (I just noticed that I am actually testing it on 2.0.8 on a Mac.)
For example, I would like to make some bit masks at compile time, which can be used in the rest of the code. Like this:
proc bitMask(bits: varargs[int]): int =
result = 0
...
const
init_portB = bitMask(1,2,5)
There is already setBits macro in bitops:
macro setBits(v: typed; bits: varargs[typed]): untyped
var v = 0b0000_0011'u8
v.setBits(3, 5, 7)
doAssert v == 0b1010_1011'u8
I would like to reuse this macro. I.e. hide the temporary variable var v in a proc or another macro, which forwards the varargs to setBits:
import bitops
proc bitMask(bits: varargs[int]): int =
result = 0
setBits(result, *varargs)
Is it possible to do?
Just to note, of course, this bitMask could be implemented with bitwise operators like this:
proc bitMask(bits: varargs[int]): int =
result = 0
for bit in bits:
result = result or (1.shl bit)
I don't really care about this specific case. The important point is whether varargs work in general. Also, in case of setBits, it is a macro that returns untyped. I.e. it works on Nim nodes. So, I wonder if something breaks when you pass typed varargs[int] up the compilation chain to untyped nodes. I guess it should work fine here, because the argument is typed varargs[typed].