Julia macro to code variables dynamically, eg creating a set of dataframes

Viewed 176

Im trying to learn macros so i thought a simple step would be to write a macro that codes a variable based on a dataframe. I could manually set df1 through dfn, but i dont want to.

For example :

macro mac(i)
    quote
        df$i = DataFrame(CSV.File("~/dev/book$i.csv"))
    end
end

If i test, in goes 2, but all that comes out is some weird string . . .

@mac(2)

df2 
>> #416#$

2 Answers

Variables in macros are "randomized" to not conflict with variables in the code where the macro expands in, see the section about metaprogramming and in particular the section about macro hygiene. @macroexpand is a very useful tool that lets you see the expanded code and makes it easier to debug.

In this case you need to "escape" the symbol.

julia> macro mac(i)
           quote
               df$i = DataFrame(CSV.File("book$i.csv"))
           end
       end
@mac (macro with 1 method)

julia> macro mac2(i)
           quote
               $(esc(Symbol("df$i"))) = DataFrame(CSV.File("book$i.csv"))
           end
       end
@mac2 (macro with 1 method)

julia> @macroexpand @mac 1
quote
    #= REPL[10]:3 =#
    var"#4#\$"(var"#5#df", var"#6#i") = begin
            #= REPL[10]:3 =#
            Main.DataFrame((Main.CSV).File("book$(var"#6#i").csv"))
        end
end

julia> @macroexpand @mac2 2
quote
    #= REPL[11]:3 =#
    df2 = Main.DataFrame((Main.CSV).File("book$(Main.i).csv"))
end

There are much simpler tools to accomplish this than using metaprogamming. The easiest way would be to just define a function that returns the DataFrame you want.

load_df(i) = DataFrame(CSV.File("~/dev/book$i.csv"))

You could then use this basically the same as your macro.

julia> df2 = load_df(2)

To load all of them at once, you could use a comprehension.

dfs = [DataFrame(CSV.File("~/dev/book$i.csv")) for i in irange]
df2 = dfs[2]
Related