Reflection capabilities

We saw in this chapter that code in Julia is represented by expressions that are data structures of the Expr type. The structure of a program and its types can therefore be explored programmatically just like any other data. This means that a running program can dynamically discover its own properties, which is called reflection. We have already encountered some of these macros or functions before:

  • Use the @isdefined macro to check whether a variable is already declared, for example if a is not declared, you get:
@isdefined a #> false
  • Use the typeof and InteractiveUtils.subtypes to query the type hierarchy (refer to Chapter 6, More on Types, Methods, and Modules)
  • Use the methods(f) to see all the methods of a function f (refer to Chapter 3, Functions)
  • names and types: given a type Person:
mutable struct Person 
    name:: String 
    height::Float64 
end 

Then, fieldnames(Person) returns the field names as a tuple of symbols: (:name, :height)

Person.types returns a tuple with the field types (String, Float64).

  • To inspect how a function is represented internally, you can use code_lowered:
code_lowered(+, (Int, Int)) 

This returns the following output:

1-element Array{Core.CodeInfo,1}:
  CodeInfo(
 53 1 ─ %1 = Base.add_int(%%x, %%y)::Any                                     │
    └──      return %1                                                       │
 )
  

Or you can use code_typed to see the type-inferred form:

code_typed(+, (Int, Int)) 

This returns the following:

1-element Array{Any,1}:
 1-element Array{Any,1}:
  CodeInfo(
 53 1 ─ %1 = Base.add_int(%%x, %%y)::Int64                                   │
    └──      return %1                                                       │
 ) => Int64
  
Using code_typed can show you whether your code is type-optimized for performance: if the Any type is used instead of an appropriate specific type that you would expect, then the type annotation in your code can certainly be improved, leading most likely to speeding up the program's execution.
  • To inspect the code generated by the LLVM engine, use code_llvm, and, to see the assembly code generated, use code_native (refer to the How Julia works section in Chapter 1, Installing the Julia Platform).

While reflection is not necessary for many of the programs that you will write, it is very useful for IDEs to be able to inspect the internals of an object, as well as for tools generating automatic documentation, and for profiling tools. In other words, reflection is indispensable for tools that need to inspect the internals of code objects programmatically.

You should also look at the MacroTools package (from Mike Innes) which has some good examples of macros.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.218.226