Femto Trader
Femto Trader

Reputation: 2014

Metaprogramming Julia functions with args and keyword args

I would like to build automatically many Julia functions (metaprogramming) to wrap a library.

Here is the function I would like to generate:

function myfunc(a::Array{Float64,1}, b::Array{Float64,1}; x=Int64(1), y=Float64(2))
    x + y
end

here are parameters of the function I would like to use to generate such a function.

funcname = :my_func
args = (:a, :b)
args_typ = (Array{Float64,1}, Array{Float64,1})
kw_args = (:x, :y)
kw_defval = (1, 2)
kw_typ = (Int64, Float64)

I don't feel confortable with Julia macro and http://docs.julialang.org/en/release-0.4/manual/metaprogramming/ doesn't help me much.

I also would like to be able to display function (generated) code.

My first idea (not very automated) was

macro GEN_FUNC(funcname)
    function $funcname(a, b, x=1, y=2)
        return x
    end
end

but it raises

ERROR: syntax: invalid method name "$funcname"

Upvotes: 4

Views: 721

Answers (2)

Scott Jones
Scott Jones

Reputation: 1750

I learned how to do this from reading the source code to the very nice DecFP.jl package (https://github.com/stevengj/DecFP.jl), by Steven G. Johnson at MIT.

It uses simple loops with the @eval macro to generate all of the wrappers for the C library.

Upvotes: 0

Lutfullah Tomak
Lutfullah Tomak

Reputation: 761

You should return an expression from macros. To make code an expression, decorate your code with either :(....) or quote ... end. Also, $ is valid only for expressions and strings. Lastly, there is a hygiene issue with macros. In order to keep $funcname intact you need esc around it. Here is corrected code

julia> macro GEN_FUNC(funcname)  
           fname=esc(funcname)  
           quote  
               function $fname(a, b, x=1, y=2)  
                   return x  
               end  
           end  
       end  

julia> macroexpand(:(@GEN_FUNC testing))  
quote  # none, line 4:  
    function testing(#21#a,#22#b,#23#x=1,#24#y=2) # none, line 5:  
        return #23#x  
    end  
end

Update: Here is how myfunc can be manually constructed (Hint:I made it an expression with quote ... end and cheated from that)

julia> f_body=:(x+y)
:(x + y)

julia> f_parameters=Expr(:parameters, Expr(:kw,:x,Int64(1)), Expr(:kw,:y,Float64(2)))
:($(Expr(:parameters, :(x=1), :(y=2.0))))

julia> f_call=Expr(:call,:myfunc,f_parameters,:(a::Array{Float64,1}),:(b::Array{Float64,1}))
:(myfunc(a::Array{Float64,1},b::Array{Float64,1}; x=1,y=2.0))

julia> f_declare=Expr(:function,f_call,f_body)
:(function myfunc(a::Array{Float64,1},b::Array{Float64,1}; x=1,y=2.0)
        x + y
    end)

julia> eval(f_declare)
myfunc (generic function with 1 method)

julia> myfunc(2,3)
ERROR: MethodError: `myfunc` has no method matching myfunc(::Int64, ::Int64)

julia> myfunc([2.],[3.])
3.0

julia> myfunc([2.],[3.];x=4,y=8.)
12.0

Upvotes: 7

Related Questions