@Mukulch15 Hmm, that’s interesting! … I also see it for first time.
Let’s assume that status
as atom
is :ok
and response
as map
is %{}
.
From what I understand after seeing code this gives us:
status = :ok
response = %{}
reply = status
# or
reply = {status, response}
That’s said I think that such code would be much more readable:
@type reply :: status | {status, response :: map()} when status: :atom
However … it does not work …
** (CompileError) iex:2: invalid type specification: reply :: status | {status, response :: map()} when status: :atom
(elixir 1.11.2) lib/kernel/typespec.ex:911: Kernel.Typespec.compile_error/2
(stdlib 3.13.2) lists.erl:1267: :lists.foldl/3
(elixir 1.11.2) lib/kernel/typespec.ex:226: Kernel.Typespec.translate_typespecs_for_module/2
(elixir 1.11.2) src/elixir_erl_compiler.erl:12: anonymous fn/3 in :elixir_erl_compiler.spawn/2
I was really surprised seeing this, because I thought that’s supported when it’s actually not!
I have navigated to:
What I found surprising is that’s supported, but only in @spec
(there are no equivalent examples for @type
). This means we can write:
iex> defmodule Example do
...> @spec reply() :: status | {status, response :: map()} when status: :atom
...> def reply, do: :ok
...> end
{:module, Example,
<<70, 79, 82, 49, 0, 0, 5, 32, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 142,
0, 0, 0, 15, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:reply, 0}}
Summary:
- It looks like
@type
have limited functionality compared to @spec
i.e. it does not support guards.
- It looks like code you mentioned is using some kind of workaround for
@type
limitation.
Note: This is only my opinion after a quick analyze which may or may not be confirmed by it’s maintainers like @chrismccord.