Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

PowerAssertEx ⭐ 153 github.com/ma2gedev/power_assert_ex

Slide 4

Slide 4 text

My Keyboard

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Dive into Elixir v1.6 Code Formatter !

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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")

Slide 10

Slide 10 text

But is it safe to format?

Slide 11

Slide 11 text

In Elixir

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

Why is it safe? What is same AST mean?

Slide 14

Slide 14 text

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 #

Slide 15

Slide 15 text

Detail of formatting process with --check-equivalent option 1. generate formatted code from original code • ! -> " 2. generate AST both the codes • ! -> # • " -> # 3. then compare • # ≒ #

Slide 16

Slide 16 text

Let's experiment

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

:elixir.string_to_quoted!/4 • this function generates AST from the code

Slide 19

Slide 19 text

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"]]}] ] }

Slide 20

Slide 20 text

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"]]}] ] }

Slide 21

Slide 21 text

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"]]}]

Slide 22

Slide 22 text

Code formatting is safe with --check-equivalent option $ mix format --check-equivalent

Slide 23

Slide 23 text

Recap • Elixir's code formatter can compare formatted code with original one at AST level so its safely to use

Slide 24

Slide 24 text

Thanks ! M3 Tech Talk #87 2018/02/16 #m3dev @ma2ge