Dive into Elixir v1.6 Code Formatter

Dive into Elixir v1.6 Code Formatter

Speaking about that Elixir code formatter is safe.

M3 Tech Talk #87 2018/02/16 #m3dev

509e5167fdb3871d6b6e045e34a3e019?s=128

Takayuki Matsubara

February 16, 2018
Tweet

Transcript

  1. Deep Dive into Elixir v1.6 Code Formatter In 7 Minutes

  2. Who am I? me |> name # Takayuki "Taka" Matsubara

    |> job # Software Engineer |> work_at # M3, Inc. |> like # Ruby, Elixir and OSS |> twitter # ma2ge |> github # ma2gedev |> oss # PowerAssertEx, bundle-star, breadcrumble, # chrono_logger, faraday-encoding
  3. PowerAssertEx ⭐ 153 github.com/ma2gedev/power_assert_ex

  4. My Keyboard

  5. Deep Dive into Elixir v1.6 Code Formatter In 7 Minutes

  6. Deep Dive into Elixir v1.6 Code Formatter In 7 Minutes

  7. Dive into Elixir v1.6 Code Formatter !

  8. Code Formatter • like gofmt • https:/ /golang.org/cmd/gofmt/

  9. Formatting code in Elixir • The mix format command formats

    your code # Elixir lang example ## before IO . puts ("Elixir is Nice") ## after `mix format` IO.puts("Elixir is Nice")
  10. But is it safe to format?

  11. In Elixir

  12. It's safe with --check-equivalent option $ mix format --check-equivalent check

    if the file after formatting has the same AST. If the ASTs are not equivalent, it is a bug in the code formatter. This option is recommended if you are automatically formatting files. — https:/ /hexdocs.pm/mix/1.6.1/ Mix.Tasks.Format.html
  13. Why is it safe? What is same AST mean?

  14. What is AST? • AST is Abstract Syntax Tree !

    • Elixir's internal representation of code • Elixir parses code into AST before executing your program • Same AST means that code behavior is also same Code ! -> AST " -> ... -> Execute #
  15. Detail of formatting process with --check-equivalent option 1. generate formatted

    code from original code • ! -> " 2. generate AST both the codes • ! -> # • " -> # 3. then compare • # ≒ #
  16. Let's experiment

  17. Example code # before defmodule My do; def coooolest do;

    "one-liner"; end; end # after `mix format` defmodule My do def coooolest do "one-liner" end end
  18. :elixir.string_to_quoted!/4 • this function generates AST from the code

  19. Original code's AST iex(1)> string1 = "defmodule My do; def

    coooolest do; \"one-liner\"; end; end" "defmodule My do; def coooolest do; \"one-liner\"; end; end" iex(2)> :elixir.string_to_quoted!(to_charlist(string1), 1, "nofile", []) { :defmodule, [line: 1], [ {:__aliases__, [line: 1], [:My]}, [do: {:def, [line: 1], [{:coooolest, [line: 1], nil}, [do: "one-liner"]]}] ] }
  20. Formatted code's AST iex(1)> string2 = """ ...(1)> defmodule My

    do ...(1)> def coooolest do ...(1)> "one-liner" ...(1)> end ...(1)> end ...(1)> """ "defmodule My do\n def coooolest do\n \"one-liner\"\n end\nend\n" iex(2)> :elixir.string_to_quoted!(to_charlist(string2), 1, "nofile", []) { :defmodule, [line: 1], [ {:__aliases__, [line: 1], [:My]}, [do: {:def, [line: 2], [{:coooolest, [line: 2], nil}, [do: "one-liner"]]}] ] }
  21. Compare both of ASTs • The diff shows almost same

    but [line: X] is indifferent ! • But this is metadata so it does not affect behavior " # diff + [do: {:def, [line: 2], [{:coooolest, [line: 2], nil}, [do: "one-liner"]]}] - [do: {:def, [line: 1], [{:coooolest, [line: 1], nil}, [do: "one-liner"]]}]
  22. Code formatting is safe with --check-equivalent option $ mix format

    --check-equivalent
  23. Recap • Elixir's code formatter can compare formatted code with

    original one at AST level so its safely to use
  24. Thanks ! M3 Tech Talk #87 2018/02/16 #m3dev @ma2ge