【Elixir】v1.14でリリースされたdbg/2が想像以上に便利だった
2022/09/01、Elixirのv1.14がリリースされました🎉
以下の公式ブログにv1.14のリリース機能がまとまっています。
目玉機能として dbg/2
の導入があるのですが、リリース前に見ていた肌感だと「便利なIO.inspect」ぐらいにしか捉えていなかったのですが、ブログ内にある「IEx+dbg」の挙動が使い勝手が良さそうでしたので、改めて dbg/2
の挙動を紹介してみます。
dbgを引数なしで使う
まずは基本的な使い方です。引数なしで dbg
を実行すると、該当行で束縛している変数の情報を確認できます。
x = 1
a = %{b: 1, c: 2}
uri = URI.parse("https://example.com")
dbg()
$ elixir sample.exs
[sample.exs:5: (file)]
binding() #=> [
a: %{b: 1, c: 2},
uri: %URI{
scheme: "https",
authority: "example.com",
userinfo: nil,
host: "example.com",
port: 443,
path: nil,
query: nil,
fragment: nil
},
x: 1
]
dbgをpipeにつなげて使う
dbg/2
をpipeにつなげて実行すると、pipeの各行の処理結果を確認できます。これが強力で、IO.inspect
で確認していた作業はすべて dbg
で行えるようになりました。
1..10
|> Enum.map(fn x -> x * x end)
|> Enum.filter(fn x -> rem(x, 2) == 0 end)
|> Enum.sum()
|> dbg()
$ elixir sample_pipe.exs
[sample_pipe.exs:5: (file)]
1..10 #=> 1..10
|> Enum.map(fn x -> x * x end) #=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|> Enum.filter(fn x -> rem(x, 2) == 0 end) #=> [4, 16, 36, 64, 100]
|> Enum.sum() #=> 220
IExで実行するとステップ実行になる!
上記のpipeと組み合わせて使うだけでも十分便利なのですが、dbg/2
をIExで利用すると行単位でのステップ実行が可能になります!
試しに実行してみます。Request to pry
との表示が出て、その後 Y
で許可すると iex(1)>
の部分が pry(1)>
となっています。
$ iex sample_pipe.exs
Erlang/OTP 24 [erts-12.0.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]
Request to pry #PID<0.108.0> at sample_pipe.exs:1
1: 1..10
2: |> Enum.map(fn x -> x * x end)
3: |> Enum.filter(fn x -> rem(x, 2) == 0 end)
4: |> Enum.sum()
Allow? [Yn] Y
Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
pry(1)>
pipe1つ1つがbreakpointとなっており next
または n
を入力すると処理を進めることができます。
pryの挙動を詳しく知りたい場合はIExのドキュメントを見ると良いでしょう。
pry(1)> n
1..10 #=> 1..10
Break reached: sample_pipe.exs:2
1: 1..10
2: |> Enum.map(fn x -> x * x end)
3: |> Enum.filter(fn x -> rem(x, 2) == 0 end)
4: |> Enum.sum()
5: |> dbg()
pry(1)> n
|> Enum.map(fn x -> x * x end) #=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Break reached: sample_pipe.exs:3
1: 1..10
2: |> Enum.map(fn x -> x * x end)
3: |> Enum.filter(fn x -> rem(x, 2) == 0 end)
4: |> Enum.sum()
5: |> dbg()
pry(1)> n
|> Enum.filter(fn x -> rem(x, 2) == 0 end) #=> [4, 16, 36, 64, 100]
Break reached: sample_pipe.exs:4
1: 1..10
2: |> Enum.map(fn x -> x * x end)
3: |> Enum.filter(fn x -> rem(x, 2) == 0 end)
4: |> Enum.sum()
5: |> dbg()
pry(1)> n
|> Enum.sum() #=> 220
--no-pry
を指定すればこの挙動を無効にして、即座に dbg/2
の結果を確認できます。
$ iex --no-pry sample_pipe.exs
Erlang/OTP 24 [erts-12.0.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]
[sample_pipe.exs:5: (file)]
1..10 #=> 1..10
|> Enum.map(fn x -> x * x end) #=> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|> Enum.filter(fn x -> rem(x, 2) == 0 end) #=> [4, 16, 36, 64, 100]
|> Enum.sum() #=> 220
Interactive Elixir (1.14.0) - press Ctrl+C to exit (type h() ENTER for help)
iex>
この規模感だとありがたみがあまりないかもしれませんが、pipeの中の処理をさらにデバッグしたい場合に強力だと思います。便利です!
1..10
|> Enum.map(fn x -> x * x end)
|> Enum.filter(fn x ->
dbg(x) # ここもbreakpointになる
rem(x, 2) == 0
end)
|> Enum.sum()
|> dbg()
dbgをLivebookで利用する
さらにはIExだけでなく、Livebook上で dbg/2
を利用すると、pipeの結果を見つつ並べ替えたり、pipeの動作をon/offできたりといったことが可能になっています。
ぜひ前述の公式ブログ内の動画を見てみてください。以下引用してリンク貼っておきます。
まとめ
v1.14で導入された dbg/2
について紹介しました。これまでは静的に値を見たい場合は IO.inspect
を使い、動的に値を見たい場合は IEx.pry
を使って、、と使い分けていましたが、今後は dbg/2
のみでサクサクとデバッグが行えそうです。是非お試しください!
Discussion