4
votes

I have been trying to write a Julia macro that takes Cmd objects and runs them inside a loop. The catch is that I want to use the local loop variables for interpolation in the command. I would write a function and use eval(), but eval() uses the global scope and so can't see the local loop variables.

Below is a simple example that demonstrates how string interpolation works, but the command interpolation fails:

macro runcmd(cmdExpr)
    quote
        for i in 1:2
            println("i: $i")
            run($cmdExpr)
        end
    end
end
@runcmd(`echo $i`)

outputs

i: 1
ERROR: i not defined
 in anonymous at none:5

If I expand the macro I get

quote  # none, line 3:
    for #261#i = 1:2 # line 4:
        println("i: $#261#i") # line 5:
        run(Base.cmd_gen((("echo",),(i,))))
    end
end

I am guessing the #261# part that is missing from the cmd_gen argument's reference to i is related to the problem, but I don't know for sure.

1
Just curious ... what's your use case and/or motivation for wanting to do this? - rickhg12hs
Have you read the macro hygiene part of the manual? The i in your quote is not going to appear literally as an i in the generated code. - IainDunning
@rickhg12hs I am running lots of shell commands each of which is over an array of possible datasets, and the commands need to reference the dataset name. - slund
@IainDunning Thanks! I read the macro section and then skimmed the hygiene part since at the time I didn't understand how it applied. Now I see what was going on. - slund
It is subtle! Any manual improvements you can suggest would be welcome I'm sure. - IainDunning

1 Answers

2
votes

You're right that the problem is because of the mismatch between the index #261#i and the reference to it in echo $i. An easy way to resolve the problem is to escape the i used in the index:

macro runcmd(cmdExpr)
    quote
        for $(esc(:i)) in 1:2
            println("i: $i")
            run($cmdExpr)
        end
    end
end

Then we get:

julia> @runcmd(`echo $i`)
i: 1
1
i: 2
2

There's more discussion in Julia's metaprogramming documentation.