Reputation: 14561
In some languages (like Python) there are function decorators which appear like macros and sit above a function definition. Decorators provide some additional functionality to the function itself.
Does Julia support this idea of function decorators in any way? Would it be possible to use macros to accomplish the same goal?
Upvotes: 5
Views: 1877
Reputation: 6423
To expand the comment of @SilvioMayolo, Julia has pretty elegant macro capability, that is more general than the Python decorator. Indeed Julia's macro take as input any expression, and the macro can hook over the Abstract Syntax Tree to return a modified expression.
The keyword you want to look for is "metaprogramming".
Here you can find the official documentation and here a convenient tutorial.
Upvotes: 2
Reputation: 775
Here is one way to achieve this with a macro using ExprTools.jl:
import ExprTools
macro dec(decorator, inner_def)
inner_def = ExprTools.splitdef(inner_def)
outer_def = copy(inner_def)
fname = get(inner_def, :name, nothing)
if fname !== nothing
@assert fname isa Symbol
inner_def[:name] = Symbol(fname, :_inner)
end
outer_def[:body] = Expr(:call,
:($decorator($(ExprTools.combinedef(inner_def)))),
get(outer_def, :args, [])...,
get(outer_def, :kwargs, [])...,
)
return esc(ExprTools.combinedef(outer_def))
end
julia> _time(f) = (x...) -> (t0=time(); val=f(x...); println("took ", time()-t0, " s"); val)
_time (generic function with 1 method)
julia> @dec _time function foo(x, y)
return x + y
end
foo (generic function with 1 method)
julia> foo(1, 2)
took 9.5367431640625e-7 s
3
However, at least in my experience, this comes up surprisingly rarely in idiomatic Julia programs. I would first think about whether your specific problem might be better solved just by multiple dispatch with plain higher-order functions and traits, which will usually lend itself to better composability.
Upvotes: 9