defmodule MyStruct do
@guards [name: :is_binary]
defstruct [:name]
end
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
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}" endend
--
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 elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/7fcdeb0f-dfcd-405d-bd5c-563648d5f9d3%40googlegroups.com.
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 elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/5085a991-3323-4d2e-bbac-135278b0e822%40googlegroups.com.
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
@guards [active: {:in, [true, false]}]
@guards [age: {:>, [18]}]
case @guards[key] do {fun, args} -> if apply(Kernel, fun, [value | args]) do # ok else # add error end # ...end
--
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 elixir-lang-core+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/21c292a5-1f09-473c-a489-a275ff5f892e%40googlegroups.com.
--
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 elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/895a5599-2f91-4abf-aeef-81adcfdffc2d%40googlegroups.com.
You're probably better off using an ecto schema and changeset.
On Thu, May 30, 2019 at 10:27 AM Francesco Lo Franco <lofranco...@gmail.com> wrote:
Sorry to dig up this very old post, but I thought I wanted to just +1 this proposed feature because I reckon it will be extremely useful for a language such Elixir, which, besides, sees DDD being applied much more than in the past. Is there any update or news about this? I'd be happy to know more or contribute to this if helpful.--
On Monday, 6 November 2017 16:50:18 UTC, Rafał Radziszewski wrote:Hi,since I see a lot of potential in the feature I'd like to provide a couple of arguments in favour of it. I will use points for ease of discussion.1. I am not going to talk about specific implementation (through @guard property) as proposed, but generally about giving possibility to create invariants in structs, i.e. possibility to raise on instantiating struct with invalid data.2. No solution will be perfect (i.e. mentioned possibility of using Map.put/3 or manually creating struct as map through %{__struct__: MyStruct}, using those features is somehow similar to addressing raw memory in C - if you're doing it, you should expect problems), a lot can be achieved by modifying just struct/2, %MyStruct{} and %MyStruct{my_struct | key: val}, as those are prevalent in the codebase.3. Though there is possibility to define function performing those validations (i.e. it is quite common to see new/1 in a lot of libraries), there is no way to restrict creation of struct to that functions. I believe it to be a good decision, since data is just data, but it makes it quite easy to make a mistake that is hard to pin down, since no warnings or any other suggestions are issued.4. While it is correct that in general forcing users to use API is the way to go, literal struct creation is very common and in most cases correct, which can lead to confusion. It can also encourage extensive boilerplating of functions like 'new', just in case, which can be detrimental to language clarity.5. Adding invariants does not breaks the premise of validating data on boundries, it supports it. Ability to restrict field values leads to cleaner code, since it is not necessary to check input validity in every function. Raising error on invalid instantiation actually forces to perform validation on the boundry - in the place where struct is instantiated. It allows for less defensive coding, since programmer can actually assume that struct is correct.6. Matching on %Foo{} in this scenario doesn't actually cause problems, since the structure won't be even instantiated if it is wrong, unless it's manually put together from map.In general I believe that adding more possibilities to express ideas through types could really help the language.Cheers,Rafal
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 elixir-l...@googlegroups.com.
def bad(user) do
%{user | name: 5}
end
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/db5da3be-0e85-4bb8-9291-926c505fdd81%40googlegroups.com.
def bad(user) do
%{user | name: 5}
end
--
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 elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/ad8102ee-0faa-4576-a1e2-5de1fb211ee7%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Jr_4dSSWz9kuEt9xMiovPwjJ_FByProtXRuNJhRhmgCw%40mail.gmail.com.