Reflection and introspection
Juliaはさまざまなランタイムリフレクション機能を提供します。
Module bindings
Module
の公開名は、names(m::Module)
を使用することで取得でき、これは公開バインディングを表すSymbol
要素の配列を返します。names(m::Module, all = true)
は、公開ステータスに関係なく、m
内のすべてのバインディングのシンボルを返します。
DataType fields
DataType
フィールドの名前は、fieldnames
を使用して照会できます。たとえば、次の型がある場合、fieldnames(Point)
はフィールド名を表すSymbol
のタプルを返します:
julia> struct Point
x::Int
y
end
julia> fieldnames(Point)
(:x, :y)
Point
オブジェクトの各フィールドの型は、Point
変数自体のtypes
フィールドに格納されています:
julia> Point.types
svec(Int64, Any)
x
はInt
として注釈されていますが、y
は型定義で注釈が付けられていないため、y
はAny
型にデフォルト設定されます。
型は DataType
と呼ばれる構造体として表されます:
julia> typeof(Point)
DataType
fieldnames(DataType)
はDataType
自体の各フィールドの名前を返し、上記の例で観察されたtypes
フィールドの1つが含まれています。
Subtypes
DataType
の直接的なサブタイプは、subtypes
を使用してリストできます。例えば、抽象的なDataType
AbstractFloat
には4つの(具体的な)サブタイプがあります:
julia> InteractiveUtils.subtypes(AbstractFloat)
5-element Vector{Any}:
BigFloat
Core.BFloat16
Float16
Float32
Float64
このリストには任意の抽象サブタイプも含まれますが、そのさらなるサブタイプは含まれません。subtypes
の再帰的な適用を使用して、完全な型ツリーを検査することができます。
subtypes
は InteractiveUtils
内にありますが、REPLを使用すると自動的にエクスポートされます。
DataType layout
DataType
の内部表現は、Cコードとインターフェースを取る際に非常に重要であり、これらの詳細を検査するためのいくつかの関数が利用可能です。isbitstype(T::DataType)
は、T
がC互換のアライメントで格納されている場合にtrueを返します。fieldoffset(T::DataType, i::Integer)
は、型の開始に対するフィールドiの(バイト)オフセットを返します。
Function methods
任意の汎用関数のメソッドは、methods
を使用してリストできます。特定の型を受け入れるメソッドを検索するには、methodswith
を使用します。
Expansion and lowering
Metaprogramming セクションで議論されたように、macroexpand
関数は、与えられたマクロのための引用されていないおよび補間された式 (Expr
) 形式を提供します。macroexpand
を使用するには、式ブロック自体を quote
してください(さもなければ、マクロが評価され、その結果が代わりに渡されます!)。例えば:
julia> InteractiveUtils.macroexpand(@__MODULE__, :(@edit println("")) )
:(InteractiveUtils.edit(println, (Base.typesof)("")))
関数 Base.Meta.show_sexpr
と dump
は、任意の式に対して S-expr スタイルのビューと深さネストされた詳細ビューを表示するために使用されます。
最後に、Meta.lower
関数は、任意の式の lowered
形式を提供し、言語構造が代入、分岐、呼び出しなどの基本操作にどのようにマッピングされるかを理解する上で特に重要です。
julia> Meta.lower(@__MODULE__, :( [1+2, sin(0.5)] ))
:($(Expr(:thunk, CodeInfo(
@ none within `top-level scope`
1 ─ %1 = 1 + 2
│ %2 = sin(0.5)
│ %3 = Base.vect(%1, %2)
└── return %3
))))
Intermediate and compiled representations
関数の低下した形式を検査するには、特定のメソッドを表示するための選択が必要です。なぜなら、一般的な関数は異なる型シグネチャを持つ多くのメソッドを持つ可能性があるからです。この目的のために、メソッド固有のコード低下が code_lowered
を使用して利用可能であり、型推論された形式は code_typed
を使用して利用可能です。 code_warntype
は、4d61726b646f776e2e436f64652822222c2022636f64655f74797065642229_40726566
の出力にハイライトを追加します。
マシンに近づくと、関数のLLVM中間表現は code_llvm
を使用して印刷できます。そして、最終的にコンパイルされたマシンコードは code_native
を使用して利用可能です(これは、以前に呼び出されていない関数のJITコンパイル/コード生成をトリガーします)。
便利のために、上記の関数のマクロバージョンがあり、標準の関数呼び出しを受け取り、引数の型を自動的に展開します:
julia> @code_llvm +(1,1)
; @ int.jl:87 within `+`
; Function Attrs: sspstrong uwtable
define i64 @"julia_+_476"(i64 signext %0, i64 signext %1) #0 {
top:
%2 = add i64 %1, %0
ret i64 %2
}
詳細については、@code_lowered
、@code_typed
、@code_warntype
、@code_llvm
、および@code_native
を参照してください。
Printing of debug information
前述の関数とマクロは、出力されるデバッグ情報のレベルを制御するキーワード引数 debuginfo
を取ります。
julia> InteractiveUtils.@code_typed debuginfo=:source +(1,1)
CodeInfo(
@ int.jl:87 within `+`
1 ─ %1 = Base.add_int(x, y)::Int64
└── return %1
) => Int64
debuginfo
の可能な値は :none
、:source
、および :default
です。デフォルトではデバッグ情報は表示されませんが、Base.IRShow.default_debuginfo[] = :source
を設定することで変更できます。