สรุปเงื่อนไขของการ quote expression ที่มี dot (.) ของ Elixir
เมื่อวานเจอเคสที่ว่าถ้าเรามี Map แบบนี้
a = %{Body: "Hello"}
ที่ key เป็น atom แต่ว่าขึ้นต้นด้วยตัวใหญ่ แล้วถ้าเราอยากใช้ syntax ที่ใช้ dot ในการ access ค่าใน key นี้
ปกติเราก็เขียนแบบนี้
a.Body
แต่ว่าพอเขียนแบบนี้แล้วดันได้ error
** (CompileError) iex:10: invalid alias: "a.Body".
If you wanted to define an alias, an alias must expand
to an atom at compile time but it did not,
you may use Module.concat/2 to build it at runtime.
If instead you wanted to invoke a function or access a field,
wrap the function or field name in double quotes
เลยสงสัยว่าทำไมมันมอง a.Body
เป็น alisas แล้วไปพยายามไป expand a.Body
ให้ได้ atom ค่านึงออกมา
เราสามารถทำความเข้าใจว่า Elixir มันแปลงโค้ดเราไปเป็น AST (Abstract Syntax Tree) อะไรได้โดยใช้ special form macro quote
เช่นเคสนี้เราลองใช้ quote กับ a.Body
ได้แบบนี้
a = %{Body: "Hello"}
quote do
a.Body
end
AST ที่ได้ออกมาเป็นแบบนี้
{:__aliases__, [], [{:a, [], Elixir}, :Body]}
ในขณะที่ถ้า key ขึ้นต้นด้วยตัวเล็กจะได้ AST อีกแบบ
a = %{body: "Hello"}
quote do
a.body
end
{{:., [], [{:a, [], Elixir}, :body]}, [no_parens: true], []}
เพราะ quote แล้วออกมาได้ต่างกันนั่นคือเหตุผลว่าทำไม a.Body
ถึงถูกเอาไปจัดการ alias expand
ซึ่งกฎตรงนี้มีคำอธิบายใน document ของ quote ที่นี่ https://hexdocs.pm/elixir/1.11.2/Kernel.SpecialForms.html#./2-quoted-expression เอาไว้ว่า ถ้าใช้ .
จะทำให้ quote ได้ 2 แบบโดยเงื่อนไขอยู่ที่ ค่าทางขวาของ .
ถ้าค่าทางขวาขึ้นต้นด้วยตัวใหญ่ จะมองเป็น alias ถ้าเป็นตัวเล็ก จะได้ AST ที่เป็น qualified calls ปกติ
ทีนี้ถ้าเรายังอยากใช้ .
เพื่อเป็น qualified calls สำหรับ access ค่าใน map ก็ยังใช้ได้ ถ้ากลับไปอ่าน error จะมีคำแนะนำอยู่คือใช้ double quote ครอบเอาไว้แบบนี้
a = %{Body: "Hello"}
a."Body"
ซึ่งถ้า quote ดูก็จะได้แบบนี้
a = %{Body: "Hello"}
quote do
a."Body"
end
{{:., [], [{:a, [], Elixir}, :Body]}, [no_parens: true], []}
Top comments (1)
AST หน้าตาซับซ้อนมาก 😅