昨夜のElixirのifの使いかたに対しての話に参加して。メモ。
Elixirのifって、以下の通りcaseから構成されるmacroとしてKernelに定義されているのですよね。nilとfalseに一致したら else を行い、それ以外は if を行うと言う。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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の条件分岐を短く書くというだけで言うと、短期的には有用ではあるかもしれません。)