I'm onboard with the module attribute approach as it aligns with what we already have. The potential existing `@enforce` conflicts would be extremely minimal so +1 to eric's proposal.
> On May 25, 2016, at 11:11 AM, José Valim <[email protected]> > wrote: > > Thanks Mike and Parker for the feedback so far. > > Eric has proposed another approach, via module attributes: > > @enforce [:name] > defstruct [:name, :age] > > One of the benefits of using module attributes is that it matches nicely the > already supported @derive attribute: > > @derive Poison.Encoder > @enforce [:name] > defstruct [:name, :age] > > Furthermore, the module attribute composes better. For example, if we want to > support @enforce in defexception (which is based defstruct), we don't need to > change anything, it just works: > > @enforce [:message] > defexception [:message] > > The same could work with Ecto: > > @enforce [:name] > schema "users" do > ... > end > > The only downside is that a module attribute can be silently defined. For > example, someone may set @enforce [:foo, :bar] in their module for other > reasons and now they will conflict. However, in such cases we can easily > check and guarantee all fields given to @enforce are also defined in the > struct. > > Can anyone think of other pros-and-cons here? > > > > José Valim > www.plataformatec.com.br <http://www.plataformatec.com.br/> > Skype: jv.ptec > Founder and Director of R&D > > On Wed, May 25, 2016 at 4:33 PM, Parker Selbert <[email protected] > <mailto:[email protected]>> wrote: > The most recent proposal, using `enforce: [:name]` is extremely clear, and > nicely backward compatible. Overall I love the recent focus on enforcing the > presence of attributes and data integrity. > > — Parker > > > On Wed, May 25, 2016, at 02:10 AM, Mike Evans wrote: >> +1 as it solves the immediate clarity issue nicely with an undeniably strong >> word. >> >> >>> On May 25, 2016, at 2:07 AM, José Valim <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>> Given Peter's feedback, what if we define it as: >>> >>> defstruct [:name, :age], enforce: [:name] >>> >>> The idea of picking :enforce instead of :required is to avoid any possible >>> confusion that some of those fields won't be effectively present in the >>> struct. >>> >>> Thoughts? >>> >>> >>> >>> >>> José Valim >>> >>> www.plataformatec.com.br <http://www.plataformatec.com.br/> >>> Skype: jv.ptec >>> Founder and Director of R&D >>> >>> >>> >>> On Wed, May 25, 2016 at 3:07 AM, eksperimental <[email protected] >>> <mailto:[email protected]>> wrote: >>> José: great new feature. Definitely a needed one! >>> and +1 on Peter Hamilton's suggestion on how to define required fields. >>> >>> An extra feature that will save us developers a lot of headeaches is >>> the ability to define a list of accepted values per field. As as the >>> current state, functions silently fail unexpected values are given >>> >>> On Tue, 24 May 2016 23:35:34 +0000 >>> Peter Hamilton <[email protected] <mailto:[email protected]>> >>> wrote: >>> >>> > I am not a fan of the proposed signature. Generally when we have >>> > multiple clauses of different arity, we try to make them purely >>> > extensions of the first. In the proposal, we go from (fields) to >>> > (optional_fields, required_fields). While one could say that it's >>> > really (optional_fields) to (optional_fields, required_fields), I >>> > think that's changing the semantics of the current signature, which >>> > to me is all the fields. I will submit, however, that this is a bit >>> > subjective and realistically the same in practice. >>> > >>> > I would propose instead: >>> > >>> > defstruct [age: nil, name: nil], required: [:name] >>> > >>> > It not only maintains semantic backwards compatibility, but there >>> > isn't an implicit meaning behind the two different arguments. It's >>> > very clear that we have a list of arguments then an explicit list of >>> > required fields. >>> > >>> > On Tue, May 24, 2016 at 4:26 PM José Valim >>> > <[email protected] >>> > <mailto:[email protected]>> wrote: >>> > >>> > > To clarify, both :age and :name fields will be present in the >>> > > underlying User struct/map. The proposal is only about fields which >>> > > must be enforced when building the structure. >>> > > >>> > > We will likely need better names than optional/required. >>> > > >>> > > *José Valim* >>> > > www.plataformatec.com.br <http://www.plataformatec.com.br/> >>> > > Skype: jv.ptec >>> > > Founder and Director of R&D >>> > > >>> > > On Wed, May 25, 2016 at 1:17 AM, José Valim < >>> > > [email protected] >>> > > <mailto:[email protected]>> wrote: >>> > > >>> > >> Hello everyone, >>> > >> >>> > >> I would like to propose an extension to defstruct that will require >>> > >> certain fields to be given when expanding it. Here is an example: >>> > >> >>> > >> defmodule User do >>> > >> >>> > >> defstruct [age: nil], # optional >>> > >> >>> > >> [name: nil] # required >>> > >> >>> > >> end >>> > >> >>> > >> >>> > >> With this feature, %User{} will fail as the :name field was not >>> > >> specified. %User{name: "foo"} or %User{name: nil} will both work as >>> > >> expected. The main use case is to make sure all important fields >>> > >> are set when building the data. For example, we can use such >>> > >> fields in the new date time types to enforce proper data >>> > >> representation. >>> > >> >>> > >> *Extra notes* >>> > >> >>> > >> 1. The required fields are given as second argument to defstruct >>> > >> as the API must remain backwards compatibility >>> > >> >>> > >> 2. The fields are required only when building structs. Matching >>> > >> will always work without specifying any field, for example: >>> > >> %User{} = user >>> > >> >>> > >> 3. The Kernel.struct/2 function, used to build structs >>> > >> dynamically, won't check for required keys. Kernel.struct!/2 >>> > >> should be used if you want to check for required keys (and also >>> > >> check that no extra keys are given) >>> > >> >>> > >> 4. defexception will leverage the same functionality >>> > >> >>> > >> *Implementation* >>> > >> >>> > >> Implementation-wise, structs will now defined a __struct__/1 >>> > >> function, besides the regular __struct__/0 function. It has not >>> > >> been decided yet how such function will behave given it must work >>> > >> both for compile-time (%User{}) and runtime (struct! User, %{}) >>> > >> checks. >>> > >> >>> > >> *Feedback* >>> > >> >>> > >> Now it is your turn. :) >>> > >> >>> > >> *José Valim* >>> > >> www.plataformatec.com.br <http://www.plataformatec.com.br/> >>> > >> Skype: jv.ptec >>> > >> Founder and Director of R&D >>> > >> >>> > > >>> > > -- >>> > > 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] >>> > > <mailto:elixir-lang-core%[email protected]>. >>> > > To view this discussion on the web visit >>> > > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2B5b%2BxxcvMOL-n6XyJ4mcQcumTU5B0AhjaTuc7qk-0P1g%40mail.gmail.com >>> > > >>> > > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2B5b%2BxxcvMOL-n6XyJ4mcQcumTU5B0AhjaTuc7qk-0P1g%40mail.gmail.com> >>> > > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2B5b%2BxxcvMOL-n6XyJ4mcQcumTU5B0AhjaTuc7qk-0P1g%40mail.gmail.com?utm_medium=email&utm_source=footer >>> > > >>> > > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2B5b%2BxxcvMOL-n6XyJ4mcQcumTU5B0AhjaTuc7qk-0P1g%40mail.gmail.com?utm_medium=email&utm_source=footer>> >>> > > . >>> > > For more options, visit https://groups.google.com/d/optout >>> > > <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] >>> <mailto:elixir-lang-core%[email protected]>. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/20160525080713.279fe1dd.eksperimental%40autistici.org >>> >>> <https://groups.google.com/d/msgid/elixir-lang-core/20160525080713.279fe1dd.eksperimental%40autistici.org>. >>> >>> For more options, visit https://groups.google.com/d/optout >>> <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] >>> <mailto:[email protected]>. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4K5-pCjrDudw1MgXbGcwfhfn%3Da%2BpukmO00cgz1nsYg9Zg%40mail.gmail.com >>> >>> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4K5-pCjrDudw1MgXbGcwfhfn%3Da%2BpukmO00cgz1nsYg9Zg%40mail.gmail.com?utm_medium=email&utm_source=footer>. >>> For more options, visit https://groups.google.com/d/optout >>> <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] >> <mailto:[email protected]>. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/6C3AEDA3-34F1-4CED-8B4E-B1769C83D812%40silljays.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/6C3AEDA3-34F1-4CED-8B4E-B1769C83D812%40silljays.com?utm_medium=email&utm_source=footer>. >> For more options, visit https://groups.google.com/d/optout >> <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] > <mailto:[email protected]>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/1464186821.454905.618394761.3E78A7BC%40webmail.messagingengine.com > > <https://groups.google.com/d/msgid/elixir-lang-core/1464186821.454905.618394761.3E78A7BC%40webmail.messagingengine.com?utm_medium=email&utm_source=footer>. > > For more options, visit https://groups.google.com/d/optout > <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] > <mailto:[email protected]>. > To view this discussion on the web visit > https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Ji7JxRFN7fw72VNwqD%2BaqPZ3MQy7EJi-DcUztG-S1KKA%40mail.gmail.com > > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Ji7JxRFN7fw72VNwqD%2BaqPZ3MQy7EJi-DcUztG-S1KKA%40mail.gmail.com?utm_medium=email&utm_source=footer>. > For more options, visit https://groups.google.com/d/optout > <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/5526D182-2A8E-4276-A2D7-16C6640350B3%40chrismccord.com. For more options, visit https://groups.google.com/d/optout.
