Macro magic: looping over varargs printing values and symbols

macros
metaprogramming

#1

Hey,

I am embarrassed to admit that today I surrendered to Julia’s meta programming x)

What I want to do is write a macro @check a b c … which checks the varargs input in turn and prints an informative error message with both name (symbol) and value of the item that caused the trouble. So, If I want to print the variables name
as well, I guess I’ll need a macro?

macro check(x)
    name = string(x)
    :($x < 0 ? error(@sprintf("%s must be >= 0, is %.5f", $name, $x)) : true)
end

works fine for one input but I simply cannot get it to work with multiple inputs. Any attempt to loop over an input tuple x…
fails, e.g.

macro checks(x...)
    tmp = Expr(:block)
    for xx in x
        name = string(xx)
        append!(tmp.args, :($xx < 0 ? error(@sprintf("%s must be >= 0, is %.5f", $name, $xx)) : true))
    end
    return(tmp)
end

fails with: no method matching length(:Expr) .

Best,

Kevin


#2

append! appends a list to an existing list, not just a single element. You want push!. (this is a common pitfall when switching from Python :wink: ).


#3

Also note that you should esc x.


#4

@rdeits thanks, that did the job - sorry for blaming macro magic :pray:

@yuyichao, nope, escaping x does not work - I think its because I did not quote the macro body which would also be an option (I guess)

So for completeness’ sake:

macro checks(x...)
    tmp = Expr(:block)
    for xx in x
        name = string(xx)
        push!(tmp.args, :($xx < 0 ? error(@sprintf("%s must be >= 0, is %.5f", $name, $xx)) : true))    
    end
    return(tmp)
end

works for me, thanks again!


#5

I don’t know what do you mean by “not work” but anyway, expect this to break on 0.6.