I am playing with guards and I want my guard definitions to also have a typespec:
defmodule AuctionHouse.Shared.ExtraGuards do
@moduledoc """
Contains additional guards to use in functions.
"""
defguard is_pos_integer(value) when is_integer(value) and value > 0
end
So, now that I have this simple guard, I want a spec for it. However, dyalizer's suggestion doesn't strike me as exactly human readable.
@spec is_pos_integer(any) ::
{:__block__ | {:., [], [:andalso | :erlang, ...]}, [],
[{:= | {any, any, any}, list, [...]}, ...]}
defguard is_pos_integer(value) when is_integer(value) and value > 0
I believe this is likely defined as a function that takes any
as an argument but the return type is very difficult for me to understand. I assume it means it creates erlang code, like a macro, but I can't make sense of it.
The suggested spec that you get is like that because it's the spec for the AST returned by the guard, since the guard is a macro under the hood. Essentially it means you're passing your guard some code (not value), and getting back some other code.
Short answer is that you probably don't want to type this. The correct typespec could be something like:
@spec is_pos_integer(Macro.t()) :: Macro.t()
which is not very useful. I'd probably go with no spec 🙃 We take the same approach in Elixir's standard library itself. For example, Integer.is_odd/1
is a guard very similar to the is_pos_integer/1
one here, and we have no spec for that.