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)

xIntとして注釈されていますが、yは型定義で注釈が付けられていないため、yAny型にデフォルト設定されます。

型は 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 の再帰的な適用を使用して、完全な型ツリーを検査することができます。

subtypesInteractiveUtils 内にありますが、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_sexprdump は、任意の式に対して 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 を設定することで変更できます。