10
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2023

Day 17

【Elixir】 with式使った事ない人が読む記事。アンチパターン付

Last updated at Posted at 2023-12-16

使い方

二つの条件が成り立った場合に処理したいとき、普通に書くと二重のcase文になります。

def area(opts) do
  case Map.fetch(opts, :width) do
    {:ok, width} ->
      case Map.fetch(opts, :height) do
        {:ok, height} -> {:ok, width * height}
        :error -> :error
      end

    :error ->
      :error
  end
end

これを纏めて書けるのがwith式でした。

def area(opts) do
  with {:ok, width} <- Map.fetch(opts, :width),
       {:ok, height} <- Map.fetch(opts, :height) do
    {:ok, width * height}
  end
end

使いたい時あるかも。

アンチパターン

with式はelse分を使ってエラーになった時の値を書き換える事ができます。

def open_decoded_file(path) do
  with {:ok, encoded} <- File.read(path),
       {:ok, decoded} <- Base.decode64(encoded) do
    {:ok, String.trim(decoded)}
  else
    {:error, _} -> {:error, :badfile}
    :error -> {:error, :badencoding}
  end
end

{:error, _} を返した場合は、{:error, :badfile}を返す
:errorを返した場合は、{:error, :badencoding}を返す

File.readは、エラーの場合、{:error, _}を返すので、:badfile
Base.decode64(encoded) はエラーの場合、:errorを返すので、:badencoding

おお。これは、ちょっと気持ち悪い。
エラーが発生した場所と、戻り値の対応が力業な記述になってます。
一見しただけでは、動作が読み取れません。

将来的に、withの中に別の処理を加えたり、返値の型が変わったら大変な事になります。

次のように書くのがおすすめです。

def open_decoded_file(path) do
  with {:ok, encoded} <- file_read(path),
       {:ok, decoded} <- base_decode64(encoded) do
    {:ok, String.trim(decoded)}
  end
end

defp file_read(path) do
  case File.read(path) do
    {:ok, contents} -> {:ok, contents}
    {:error, _} -> {:error, :badfile}
  end
end

defp base_decode64(contents) do
  case Base.decode64(contents) do
    {:ok, decoded} -> {:ok, decoded}
    :error -> {:error, :badencoding}
  end
end

else文の使い道を間違えないようにしましょう。

説明のプログラムは、hexdocsの説明のプログラムから引用しました。

本家の説明
https://hexdocs.pm/elixir/1.16.0-rc.0/Kernel.SpecialForms.html#with/1
https://hexdocs.pm/elixir/1.16.0-rc.0/code-anti-patterns.html#complex-else-clauses-in-with

10
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?