defmodule User do
defstruct [age: nil], # optional
[name: nil] # required
end
Why require a value for the required fields? I.e. :name vs [name: nil]. If it's required, the nil value seems verbose.
(On mobile, apologies for poor explanation)
--
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/CAGnRm4KYeJCq7u2iubGoNSnNS5y94o5Ju8_xs_n9PZ_Q1OTKRg%40mail.gmail.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-co...@googlegroups.com.
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAOtk34cFt09TnKccLerF7WJ2d66kUO2rcJqZ09NBKq2DB9qJ%2Bw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/bede9a4c-8428-4447-bda1-c77eccd64893%40googlegroups.com.
Thanks Peter! Figured I had to be missing something.
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/rW8c3_xSVCg/unsubscribe.
To unsubscribe from this group and all its topics, 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/CAOMhEnyNx3O%3D7QEk3Cw-Spvqaw6Ve1RpozVE6t_nsxQ8sxFU6Q%40mail.gmail.com.
defstruct [:name, :age], enforce: [:name]
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/20160525080713.279fe1dd.eksperimental%40autistici.org.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4K5-pCjrDudw1MgXbGcwfhfn%3Da%2BpukmO00cgz1nsYg9Zg%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/6C3AEDA3-34F1-4CED-8B4E-B1769C83D812%40silljays.com.
@enforce [:name]
defstruct [:name, :age]
@derive Poison.Encoder
@enforce [:name]
defstruct [:name, :age]
@enforce [:message]
defexception [:message]
@enforce [:name]
schema "users" do
...
end
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/1464186821.454905.618394761.3E78A7BC%40webmail.messagingengine.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Ji7JxRFN7fw72VNwqD%2BaqPZ3MQy7EJi-DcUztG-S1KKA%40mail.gmail.com.
I like this feature a lot, but dislike the term enforce
. IMO, it muddies things and is much less clear than require
. In my experience, the term required
is generally used to indicate fields that must be present. For example, JSON schema uses that term. enforce
gives me the sense that some kind of validation policy is applied but does not describe what the validation policy is. Does it enforce the type of values allowed for the named fields? Does it enforce the fields are present? Does it enforce the named fields are not present? Does enforce: [:percent]
validate that percent
is between 1 and 100?
Obviously, given there is no further information provided with the struct definition, it would be reasonable to assume that it means that the presence of the named fields is enforced, but I fail to see how enforce
is preferable to require
.
Regardless of which word is chosen, I think it would be easy to write the past-tense form of the word (e.g. enforced
or required
instead of enforce
or require
). With the keyword argument approach, defstruct
could provide an nice error when you use the wrong form. With the module attribute approach, it wouldn’t really make sense to detect that, since module attributes can be user-defined and any attribute is valid.
So I would vote in favor of:
defstruct [:name, :age], require: [:name]
…and also ask that it provides a nice error if you use required:
or any other invalid option.
Myron
In fact, I wonder why is derive an attribute, and not an option?
In fact, I wonder why is derive an attribute, and not an option?For all the reasons said above. :)
--
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/CAGnRm4LLqwY2ErB7yNQJXweq1pVU8gxwCg3mkcym_RczFsNDCA%40mail.gmail.com.
I like this feature a lot, but dislike the term
enforce
. IMO, it muddies things and is much less clear thanrequire
. In my experience, the termrequired
is generally used to indicate fields that must be present. For example, JSON schema uses that term.enforce
gives me the sense that some kind of validation policy is applied but does not describe what the validation policy is. Does it enforce the type of values allowed for the named fields? Does it enforce the fields are present? Does it enforce the named fields are not present? Doesenforce: [:percent]
validate thatpercent
is between 1 and 100?
That's a very good point. I believe :require is better than :required (thanks for that) but I still believe the require/required connotation can be confusing. Also require may be a bit overloaded in Elixir (given the require special form and Code.require_file). Can you think of other options? :)
--
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/C87C5A29-BB52-454D-8CAF-6534F34310B7%40chrismcg.com.
I like this feature a lot, but dislike the term
enforce
. IMO, it muddies things and is much less clear thanrequire
. In my experience, the termrequired
is generally used to indicate fields that must be present. For example, JSON schema uses that term.enforce
gives me the sense that some kind of validation policy is applied but does not describe what the validation policy is. Does it enforce the type of values allowed for the named fields? Does it enforce the fields are present? Does it enforce the named fields are not present? Doesenforce: [:percent]
validate thatpercent
is between 1 and 100?That's a very good point. I believe :require is better than :required (thanks for that) but I still believe the require/required connotation can be confusing. Also require may be a bit overloaded in Elixir (given the require special form and Code.require_file). Can you think of other options? :)
I like this feature a lot, but dislike the term
enforce
. IMO, it muddies things and is much less clear thanrequire
. In my experience, the termrequired
is generally used to indicate fields that must be present. For example, JSON schema uses that term.enforce
gives me the sense that some kind of validation policy is applied but does not describe what the validation policy is. Does it enforce the type of values allowed for the named fields? Does it enforce the fields are present? Does it enforce the named fields are not present? Doesenforce: [:percent]
validate thatpercent
is between 1 and 100?That's a very good point. I believe :require is better than :required (thanks for that) but I still believe the require/required connotation can be confusing. Also require may be a bit overloaded in Elixir (given the require special form and Code.require_file). Can you think of other options? :)
The one thing I don't like about using options with defstruct is that I tend to define my structs with the keyword list syntax, defining default values - if I want to do that *and* define required fields, I now have to wrap the definition of the fields+defaults in a list, i.e.: defstruct [foo: "bar", baz: :qux, bar: nil], required: [:foo, :baz] Granted, that's not a big deal, but I like the following much better: @required [:foo, :baz] defstruct foo: "bar", baz: :qux, bar: nil That said, I don't disagree with your reasoning, but I think the ship has already sailed with regards to precedent (i.e. `derive`). Paul |
--
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/0A95E06E-8689-4D3C-954E-17046EEBDB8E%40gmail.com.
Also, it’s a stretch, but it’s possible that a sloppy programmer separates these expressions, say by inserting a multiline comment, a typespec, or even something completely unrelated. Then it becomes harder to spot the complete specification of the struct.
Say I want to move the struct to another module, I have to pay attention to move all three expressions (which might be separated by some other not necessarily struct related stuff). Or say in my macro which defines a struct, I want to prevent some option (e.g. require).
if some_condition? do... some code ...defstructelse
defstruct
end
In contrast, having these macros accept valid options as arguments allows us to specify the struct in a single expression (which IMO reads nicer). It makes the interface more explicit about what’s accepted
On 25 May 2016, at 18:46, José Valim <jose....@plataformatec.com.br> wrote:Also, it’s a stretch, but it’s possible that a sloppy programmer separates these expressions, say by inserting a multiline comment, a typespec, or even something completely unrelated. Then it becomes harder to spot the complete specification of the struct.Sloppy programmers will break all kinds of code. I generally really dislike the sloppy programmer argument. Do we really want to guide our decisions based on programmers that are sloppy?
Say I want to move the struct to another module, I have to pay attention to move all three expressions (which might be separated by some other not necessarily struct related stuff). Or say in my macro which defines a struct, I want to prevent some option (e.g. require).If you are moving code around, you always need to pay attention. :) What if you are defining the struct like this:if some_condition? do... some code ...defstructelsedefstructendIf you get the first defstruct and ignore the rest... it will be wrong.
All other things being equal or very similar, I think the interface which prevents sloppiness is better.
It will break on compile, hinting me that I didn’t move the complete code. Yes, I need to pay attention, but compiler has my back.
The latter approach means I have to know the semantics of @derive, @require and defstruct/defexception/schema, to know that these things tie together.
--
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/CAGnRm4%2BicfA9Z%3DesQ%3Dw08XmtD_LvQKF2f4%3DEYx_N96fhL8FB5g%40mail.gmail.com.
The “composability” of module attribute is really an equivalent of a global var. One expression sets something into the context, and another, seemingly unrelated expression depends on it.
@doc "Delegates to Foo.bar"
@spec bar() :: Foo.bar
defdelegate bar(), to: Foo
A trade-off which IMO does exist is opt-in vs opt-out. With params, each macro writer needs to explicitly allow the supported options. With module attributes, these are implicitly available without writing a single line of code.
It’s worth pointing out that this trade-off revolves around writers of macros which use structs. For users of macros, I think the difference between two approaches is mostly aesthetic.
--
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/a9bd4321-4e3f-49a7-84af-95951e5fdb29%40googlegroups.com.
On 25 May 2016, at 20:23, José Valim <jose....@plataformatec.com.br> wrote:Constructs like imports and aliases would also perfectly fit your definition of "one expression sets something into the context, and another, seemingly unrelated expression depends on it". Aliases, in particular, wouldn't give any compile time guarantee. And those aren't global variables either.
defmodule User do
defstruct [age: nil, name: nil]
end
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 dodefstruct [age: nil], # optional[name: nil] # requiredendWith 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 compatibility2. The fields are required only when building structs. Matching will always work without specifying any field, for example: %User{} = user3. 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. :)
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4LAy%2BnyO0bv5tpuA0TYRYgHMtYLtryPYpe1s3smX0OM8g%40mail.gmail.com.--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/rW8c3_xSVCg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-lang-co...@googlegroups.com.
First off, I like the required_keys
as the name for the option.
As for module attribute vs keyword option: I favor the keyword option approach for the same reasons that Saša outlined. The module attribute option uses an imperative, global state approach that feels like the equivalent of this:
String.split_options(parts: 3)
String.split("1,2,3,4", ",")
…and yet I expect everyone is glad that the Elixir API instead puts parts
as a keyword option on the split
call:
String.split("1,2,3,4", ",", parts: 3)
If we favor options being passed as explicit arguments in general, it’s not clear to me it’s better to use the imperative global state approach here.
All that said: I understand the composability argument for the module attribute (although, that argument could also apply to anytime a new option is being introduced to any API — and yet we would normally favor passing new options as an explicit argument) and will be glad to see this feature in whatever form it takes.
Myron
--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/rW8c3_xSVCg/unsubscribe.
To unsubscribe from this group and all its topics, 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/78274dc5-4099-4036-b920-c51214ad2e66%40googlegroups.com.
The module attribute option uses an imperative, global state approach that feels like the equivalent of this
String.split_options(parts: 3) String.split("1,2,3,4", ",")
String.split_options(__MODULE__, parts: 3) String.split(__MODULE__, "1,2,3,4", ",")
On 25 May 2016, at 22:06, Michał Muskała <mic...@muskala.eu> wrote:2016-05-25 19:30 GMT+02:00 Saša Jurić <sasa....@gmail.com>:defstruct which takes parameters is composable. Any macro that uses defstruct can take the same parameters (or some subset), and pass them to defstruct, and it will work. It can also take some different parameters, and derive from them the ones that needs to be passed to defstruct.
The problem here is that library needs to explicitly support it, so
you can't use a new feature with old code without changing it.
Another, even bigger issue, is backward compatibility in libraries.
If we wanted to support that in Ecto, while supporting both Elixir 1.2
without this feature and 1.3 with this feature is to check elixir
version and add multiple ifs, in various places. This is not bearable
and I suspect most libraries will either break backwards compatibility
or simply ignore this feature.
Definition of a function in a module is side effect free as the order you define functions does not matter. The definition is atomic.
In case of exceptions and Ecto macros that could benefit from this or more additional arguments to defstruct. Why not to take all the unexpected additional arguments (for example in defexception) and pass them to defstruct explicitly? And defstruct will decide what to do with them.
As attributes are not parameters how to decide where they might be documented?
--
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/CAGnRm4LxVGykfbLz7mq%3DfiY06pfeKWP21h-RBwvgKhBFBh_6%3DQ%40mail.gmail.com.
--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-core" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-core/rW8c3_xSVCg/unsubscribe.
To unsubscribe from this group and all its topics, 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/FE38208F-B0D5-4BBA-A4D2-1A06D68733CE%40gmail.com.