Reflection and introspection¶
Julia provides a variety of runtime reflection capabilities.
The exported names for a
Module are available using
names(m::Module), which will return
an array of
Symbol elements representing the exported bindings.
names(m::Module,true) returns symbols for all bindings in
m, regardless of export status.
The names of
DataType fields may be interrogated
fieldnames(). For example, given the following type,
fieldnames(Point) returns an arrays of
elements representing the field names:
The type of each field in a
Point object is stored in the
types field of the
Point variable itself:
x is annotated as an
y was unannotated in the type definition, therefore
y defaults to the
Types are themselves represented as a structure called
fieldnames(DataType) gives the names for each field of
DataType itself, and
one of these fields is the
types field observed in the example above.
The direct subtypes of any
DataType may be listed using
subtypes(). For example, the abstract
has four (concrete) subtypes:
Any abstract subtype will also be included in this list, but further subtypes
thereof will not; recursive application of
subtypes() may be used to inspect
the full type tree.
The internal representation of a
DataType is critically important when interfacing with
C code and several functions are available to inspect these details.
isbits(T::DataType) returns true if
stored with C-compatible alignment.
fieldoffsets(T::DataType) returns the (byte) offset for each
field relative to the start of the type.
The methods of any generic function may be listed using
methods(). The method dispatch
table may be searched for methods accepting a given type using
Expansion and lowering
As discussed in the Metaprogramming section, the
macroexpand() function gives the unquoted and interpolated expression (
for a given macro. To use
quote the expression block itself (otherwise,
the macro will be evaluated and the result will be passed instead!). For example:
dump() are used to display S-expr style views
and depth-nested detail views for any expression.
expand() function gives the
lowered form of any expression and is of particular
interest for understanding both macros and top-level statements such as function declarations and
julia>expand(:(f()=1)):($(Expr(:method,:f,:((top(svec))((top(apply_type))(Tuple),(top(svec))())),AST(:($(Expr(:lambda,Any,Any[Any,Any,0,Any],:(begin# none, line 1:return1end))))),false)))
Intermediate and compiled representations
Inspecting the lowered form for functions requires selection of the specific method to display,
because generic functions may have many methods with different type signatures. For this purpose,
method-specific code-lowering is available using
and the type-inferred form is available using
highlighting to the output of
code_typed() (see @code_warntype).
Closer to the machine, the LLVM intermediate representation of a function may be printed using by
code_llvm(f::Function,(Argtypes...)), and finally the compiled machine code is
code_native(f::Function,(Argtypes...) (this will trigger JIT
compilation/code generation for any function which has not previously been called).
For convenience, there are macro versions of the above functions which take standard function calls and expand argument types automatically: