Such changes are not as straight-forward because then most would expect
matching on %Foo{} to also validate on those guards and that comes with its
own set of problems:

1. we will need changes in the compiler to make this work

2. if we are checking the fields for %Foo{} on every pattern matching, it
becomes unnecessary overhead

3. it is unclear how such features will play against other features in the
language, such as defguard

Given we need to validate data in the boundaries, my proposal is to keep
validating those in the boundaries instead of every time %Foo{} is used.




*José Valimwww.plataformatec.com.br
<http://www.plataformatec.com.br/>Founder and Director of R&D*

On Wed, Oct 4, 2017 at 11:08 AM, Maciej Kaszubowski <
[email protected]> wrote:

> Hello,
>
> *Proposed feature*
>
> I'd like to propose another improvement on structs. Inspired by @enforce_keys,
> I'd like to propose adding @guards which can help to validate the types of
> the fields in the struct.
>
> Example usage:
>
> defmodule MyStruct do
>   @guards [name: :is_binary]
>   defstruct [:name]
> end
>
>
> which will fail if the given condition is not satisfied:
>
> iex(2)> %MyStruct{name: 5}
> ** (ArgumentError) The following fields didn't match the guards: struct
> MyStruct: [{:name, :is_binary, 5}]
>     expanding struct: MyStruct.__struct__/1
>
>
> *Notes*
>
>    - As the example shows, the behaviour will be similar to @enforce_keys
>    - it will be checked only when creating the struct, not when updating
>    - Using module attribute allows to keep this optional and allows to
>    keep backwards compatibility
>
> *Possible implementation*
>
> With  https://hexdocs.pm/elixir/master/guards.html and Kernel.apply/3, we
> can modify existing def __struct__(kv) from Kernel:
>
>
> def __struct__(kv) do
>   {map, errors} =
>     Enum.reduce(kv, {@struct, {[], @enforce_keys}}, fn {key, val}, {map,
> {type_errors, key_errors}} ->
>
>       guard = @guards[key]
>       if guard && apply(Kernel, guard, [val]) do
>         {Map.replace!(map, key, val), {type_errors,
> List.delete(key_errors, key)}}
>       else
>         {
>           Map.replace!(map, key, val),
>           {[{key, guard, val} | type_errors], List.delete(key_errors, key)}
>         }
>       end
>
>     end)
>   case errors do
>     {[], []} -> map
>     {types, []} ->
>       raise ArgumentError, "The following fields didn't match the guards:
> " <>
>         "struct #{inspect __MODULE__}: #{inspect types}"
>   end
> end
>
>
>
> This, of course, needs style improvements (and validation of required
> fields which is currently removed for the sake of clarity), but this is
> only a proof of concept to verify that the implementation is possible and
> quite easy.
>
> *Why not use @type?*
>
> While it would be cool to be able to verify the types based on typespecs,
> it would be harder because I think not all types can be easily validated.
> The suggested approach with guards will be feel more familiar because we
> can already do this for functions. Adding guard validation for struct
> fields feels like reasonable step.
>
> *What do you think?*
>
> I'd be happy to start working on this feature, but I wanted to know what
> do you all think about this.
>
>
> Cheers,
> Maciej
>
> --
> You received this message because you are subscribed to the Google Groups
> "elixir-lang-core" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To view this discussion on the web visit https://groups.google.com/d/
> msgid/elixir-lang-core/7fcdeb0f-dfcd-405d-bd5c-
> 563648d5f9d3%40googlegroups.com
> <https://groups.google.com/d/msgid/elixir-lang-core/7fcdeb0f-dfcd-405d-bd5c-563648d5f9d3%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LjZhiDDVcLzODqWWUVt4W49enKBA3-JHUVhxZx4O%3DaWg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to