[Erlang][Elixir]if condition in Erlang/Elixir

昨夜のElixirのifの使いかたに対しての話に参加して。メモ。

Elixirのifって、以下の通りcaseから構成されるmacroとしてKernelに定義されているのですよね。nilfalseに一致したら else を行い、それ以外は if を行うと言う。


# https://github.com/elixir-lang/elixir/blob/v1.2.5/lib/elixir/lib/kernel.ex#L2321
defmacro if(condition, clauses) do
build_if(condition, clauses)
end
defp build_if(condition, do: do_clause) do
build_if(condition, do: do_clause, else: nil)
end
defp build_if(condition, do: do_clause, else: else_clause) do
optimize_boolean(quote do
case unquote(condition) do
x when x in [false, nil] -> unquote(else_clause)
_ -> unquote(do_clause)
end
end)
end
defp build_if(_condition, _arguments) do
raise(ArgumentError, "invalid or duplicate keys for if, only \"do\" " <>
"and an optional \"else\" are permitted")
end
# https://github.com/elixir-lang/elixir/blob/v1.2.5/lib/elixir/lib/kernel.ex#L2368
defmacro unless(condition, clauses) do
build_unless(condition, clauses)
end
defp build_unless(condition, do: do_clause) do
build_unless(condition, do: do_clause, else: nil)
end
defp build_unless(condition, do: do_clause, else: else_clause) do
quote do
if(unquote(condition), do: unquote(else_clause), else: unquote(do_clause))
end
end
defp build_unless(_condition, _arguments) do
raise(ArgumentError, "invalid or duplicate keys for unless, only \"do\" " <>
"and an optional \"else\" are permitted")
end

そして、これはErlangのifとは意味合いが異なります。Erlangの if はElixirで言う cond do ... end です。

http://elixir-lang.org/crash-course.html#if
(20160503現在)

なので、Elixirにおけるifって、Rubyといったifが条件分岐として普通な他言語から移ってくる分には良いけれど、Erlang Elixirの互換性な世界では少し混乱をもたらしてしまいます。私は若干混乱しました。。。なので、Elixirでは個人的にはifはほとんど使わない。必要になるときはパターンマッチで切り出すとか考えます。ちなみに else if とかな書き方はできなくて、その場合は当然 case ですね。

これを冗長というかどうかはそれを実装する人たちの合意形成にお任せする形になると思いますが、個人的には少し道からそれた使い方になるので必要以上に不具合つくり込みそうな感じもしています。(とはいえ、true/falseの条件分岐を短く書くというだけで言うと、短期的には有用ではあるかもしれません。)

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.