The else clause was there from the beginnings of with. Looking through Elixir’s codebase, I haven’t really found instances of using more than one patterns in else. So it’s either falling through without the else clause:
def touch(path, time) when is_tuple(time) do
path = IO.chardata_to_string(path)
with {:error, :enoent} <- :elixir_utils.change_universal_time(path, time),
:ok <- write(path, "", [:append]),
do: :elixir_utils.change_universal_time(path, time)
end
or returning a default regardless of an error:
def parse_version(string, approximate? \\ false) when is_binary(string) do
destructure [version_with_pre, build], String.split(string, "+", parts: 2)
destructure [version, pre], String.split(version_with_pre, "-", parts: 2)
destructure [major, minor, patch, next], String.split(version, ".")
with nil <- next,
{:ok, major} <- require_digits(major),
{:ok, minor} <- require_digits(minor),
{:ok, patch} <- maybe_patch(patch, approximate?),
{:ok, pre_parts} <- optional_dot_separated(pre),
{:ok, pre_parts} <- convert_parts_to_integer(pre_parts, []),
{:ok, build_parts} <- optional_dot_separated(build) do
{:ok, {major, minor, patch, pre_parts, build_parts}}
else
_other -> :error
end
end
or using the approach suggested by the author, but without a dedicated error struct:
with :ok <- make_boot_scripts(release, version_path, consolidation_path),
:ok <- make_vm_args(release, vm_args_path),
:ok <- make_vm_args(release, remote_vm_args_path),
:ok <- Mix.Release.make_sys_config(release, sys_config, config_provider_path),
:ok <- Mix.Release.make_cookie(release, cookie_path),
:ok <- Mix.Release.make_start_erl(release, start_erl_path) do
consolidation_path
else
{:error, message} ->
File.rm_rf!(version_path)
Mix.raise(message)
end
I’m not familiar with the codebase, but the last one looks like a use of with to build some flow (something that you’d use in application code) rather than just mechanics of avoiding nested case (something you’d use more in library code)


















