stevensonmt
Defining types for struct fields
I would like to have a struct in a module without default values for the fields, but I would like each field to be limited to a specific type. Is there a way to define and enforce this in Elixir?
Most Liked
lud
You can define a typespec for your struct but you cannot enforce it.
What you can do in your module is to use a constructor-like function:
def new(props) do
... validate the values
struct(__MODULE__, props)
end
(new is not a special name)
hauleth
I think that in this case struct!/2 (with bang) will make more sense.
lud
I hesitated because if you validate the values beforehand you should not have to use it, but yes it may be safer.
@stevensonmt the difference is that struct!/2 will raise if the given props have extra properties or if keys declared with @enforce_keys are not defined.
brettbeatty
You can always reduce the opts into your struct however you want. You can validate, rename, transform, do whatever.
A simple example where opts of the wrong type are simply rejected
def new(opts \\ []) do
Enum.reduce(opts, %__MODULE__{}, &put_opt/2)
end
defp put_opt(opt, acc)
defp put_opt({:a, a}, acc) when is_integer(a) do
%{acc | a: a}
end
defp put_opt({:b, b}, acc) when is_binary(b) do
%{acc | b: b}
end
defp put_opt({:c, c}, acc) when is_atom(c) do
%{acc | c: c}
end
defp put_opt(_opt, acc) do
acc
end
brettbeatty
Oh sorry it’s a personal preference when I create a function with multiple clauses to have that. In my opinion it makes it clearer what the args should be, often helps with docs (for public functions), and gives me somewhere to put @doc, @spec, etc. It’s only really required when you have multiple clauses for a function that takes default arguments. https://hexdocs.pm/elixir/Kernel.html#def/2-default-arguments








