Defining function inside a macro

What am I doing wrong? It’s giving me a syntax error… Thanks

# @makefn "fn" :hello
macro makefn(prefix, name)
    quote
        fn = prefix * "_" * name
        function $(fn)
            println("hello")
        end
    end
end
syntax: expected "end" in definition of function "($ fn)"

Calculate fn outside of the quote. That piece is calculated at compiled time, and then build the function with the name in it as what should be run at runtime.

Thanks, Chris. I also forgot about the parentheses after the function name. This works:

# @makefn "fn" "hello"
macro makefn(prefix, name)
    fn = Symbol(prefix * "_" * name)
    quote
        function $(esc(fn))()
            println("hello")
        end
    end
end
@makefn "fn" "hello"

Next challenge… Is it possible to define the function with custom number of args? maybe I would have to mess with the AST?

# @makefn "fn" "hello" :a :b :c
# => fn_hello(a,b,c) = sum([a,b,c])
macro makefn(prefix, name, args...)
    fn = Symbol(prefix * "_" * name)
    argstup = Tuple(args)
    quote
        function $(esc(fn))($(esc(argstup)))
            sum([$(esc(argstup))])
        end
    end
end
syntax: "(Expr(:quote, :a)::Any, Expr(:quote, :b)::Any, Expr(:quote, :c)::Any)" is not a valid function argument name

Just throw the splatted args into the function’s argument setup at compile time. Use macroexpand to see what it does.

I splatted it three different ways. The first two didn’t get through compilation stage so the last one seems most promising. Read on…

  1. $(esc(args...))
MethodError: no method matching esc(::Symbol, ::Symbol, ::Symbol)
  1. $(esc(args)...)
MethodError: no method matching start(::Expr)
  1. $(esc(args))...
syntax: "(:a, :b, :c)" is not a valid function argument name

Here’s what happens with the 3rd method:

julia> macro makefn3(prefix, name, args...)
           fn = Symbol(prefix * "_" * name)
           quote
               function $(esc(fn))($(esc(args))...)
                   sum([$(esc(args))...])
               end
           end
       end
@makefn3 (macro with 1 method)

julia> @makefn3 "fn" "hello" a b c
ERROR: syntax: "(:a, :b, :c)" is not a valid function argument name

julia> @macroexpand(@makefn3 "fn" "hello" a b c)
quote  # REPL[25], line 4:
    function fn_hello((:a, :b, :c)...) # REPL[25], line 5:
        (Main.sum)([(:a, :b, :c)...])
    end
end
julia> macro makefn(prefix, name, args...)
           fn = Symbol(prefix * "_" * name)
           argstup = Tuple(args)
           quote
               function $(esc(fn))($(map(esc, argstup)...))
                   sum([$(map(esc, argstup)...)])
               end
           end
       end
@makefn (macro with 1 method)

julia> @makefn "fn" "hello" a b c
fn_hello (generic function with 1 method)

julia> fn_hello(1,2,3)
6

Or $(esc.(argstup)...) instead of $(map(esc, argstup)...), works too.