-
Notifications
You must be signed in to change notification settings - Fork 0
Metaprogramming
Julia code is represented as a syntax tree built out of Julia data structures of type Expr. This makes it easy to construct and manipulate Julia code from within Julia, without generating or parsing source text. Here is the definition of Expr:
type Expr
head::Symbol
args::Array{Any,1}
typ
end
The head is a symbol identifying the kind of expression, and args is an array of subexpressions. typ is used by type inference to store type annotations (it can generally be ignored).
There is special syntax for "quoting" code (analogous to quoting strings) that makes it easy to create expression objects without explicitly constructing Exprs. There is a long form, for blocks of code, using quote ... end, and a short form using prefix :.
julia> e = :(a+b)
+(a,b)
julia> e.head
call
julia> e.args
{+,a,b}
Values of expressions may be interpolated into quote expressions with $ as in strings:
julia> a=1
1
julia> e = :($a+b)
+(1,b)
When the argument to : is just a symbol, a Symbol object results instead of an Expr.
An expression object can be evaluated (executed) at the top level scope (equivalent to loading from a file or typing at the prompt) using the eval function. This can be used in a manner similar to the C preprocessor to generate definitions that would be difficult or repetitive to write manually. For example, the following code defines a series of operators on three arguments in terms of their 2-argument forms:
for op = (:+, :*, :&, :|, :$)
eval(quote
($op)(a,b,c) = ($op)(($op)(a,b),c)
end)
end
For uses like this the pattern eval(quote ... end) occurs repeatedly, so there is a nicer equivalent macro @eval:
for op = (:+, :*, :&, :|, :$)
@eval begin
($op)(a,b,c) = ($op)(($op)(a,b),c)
end
end
Macros provide a convenient hook for rewriting syntax trees in a program. They are invoked with the following syntax:
@name arg1 arg2 ...
Before the program runs, this statement will be replaced with the result of calling an expander function for name on the expression objects of the arguments. Expanders are defined with the macro keyword:
macro name(arg1, arg2, ...)
...
end
Here is an example using a macro to define an assertion statement for debugging:
macro assert(ex)
:($ex ? true : error("Assertion failed: ", $string(ex)))
end
@assert condition will expand to a ? expression that tests the condition, and if it is false throws an error containing a string representation of the condition expression. Notice that it would not be possible to write this as a function, since only the value of the condition and not the expression that computed it would be available.
Previous: Parallel Computing — Next: Calling C Code