Fair enough, agreed about decoupling the problem. In that case I’d still offer Keyword.take!/2 that works like this:
iex> Keyword.take!([a: 1], [:a, :b]) [a: 1] iex> Keyword.take!([c: 1], [:a, :b]) ** (ArgumentError) I think take/2 and take!/2 matches struct/2 and struct!/2. > On 30 Dec 2020, at 11:30, José Valim <[email protected]> wrote: > > Wojtek, I originally thought about Map.merge!, where the second argument must > be a subset of the first. This way we can check keys and provide default > values: > > Keyword.merge!([parenthesis: 10], opts) > > However, when I tried using this in practice, I realized that default > arguments are not always straight-forward to compute. For example, you may > want to compute them lazily. You could argue we could set them to nil in said > cases, but then we'd mix the absence of a key with nil value, which may not > be desired. > > Therefore, I concluded that it is probably best to keep those problems > separated and validate only the keys. I agree with Andrea that this is small > but the benefit I see having it in core is to promote more folks to use it. > Both Python and Ruby provide at the syntax-level a convenience that checks > only the given keys are expected. So, when it comes to options, both of these > languages are allowing us to write assertive code more elegantly than Elixir. > > > On Wed, Dec 30, 2020 at 10:10 AM Wojtek Mach <[email protected] > <mailto:[email protected]>> wrote: > I think this would be a great addition to the core. > > While there are libraries in this space, as silly as this may seem, solving > this key typo problem seems like solving the 60%-80% case (not to take away > anything from those libraries!) > > How about a Keyword.take!/2? > > iex> Keyword.take!([a: 1], [:a, :b]) > [a: 1] > > iex> Keyword.take!([c: 1], [:a, :b]) > ** (ArgumentError) unknown key :c in [c: 1] > > There are however two problems with it: > > 1. would people expect that `Keyword.take!([a: 1], [:a, :b])` should fail > because `:b` is not in the input? > > Maybe the 2nd argument accepts defaults? (I know it probably starts doing > too much...) > > iex> Keyword.take!([a: 1], [:a, :b]) > [a: 1, b: nil] > > iex> Keyword.take!([a: 1], [:a, b: 2]) > [a: 1, b: 2] > > In fact this could have the following semantics: if there's no default, > it's > a required key: > > iex> Keyword.take!([], [:a, b: 2]) > ** (ArgumentError) missing required key :a > > What's nice is you can later use `Keyword.fetch!/2` that will save you from > typos. > > But that being said, If the 2nd argument accepts a keyword, then it > probably shouldn't be called `take!/2` as it no longer matches `take/2`. > > 2. If you do: `opts = Keyword.take!(..., ...)` and later `opts[:my_key]` you > still have an opportunity for a typo and you can't necessarily use > `Keyword.fetch!/2` because optional keys might not be there. > > As Devon mentioned, structs are a really cool solution because they provide > rigidity, defaults, and the assertive map access syntax with ".". Creating a > struct for every function that accepts options feels like a bit much though. > > Taking everything above into consideration, perhaps there's: > > iex> Map.something_something!([], [:name, timeout: 5000]) > ** (ArgumentError) missing required key :name > > iex> opts = Map.something_something!([name: Foo], [:name, timeout: 5000]) > iex> opts.timeout > 5000 > > and I feel like it's still relatively small addition but it's closer to the > "80% solution". No idea how to name this thing though! > > > >> On 30 Dec 2020, at 09:36, Devon Estes <[email protected] >> <mailto:[email protected]>> wrote: >> >> Typos are extremely hard to prevent in dynamic data structures since >> validations need to be implemented at the point of use instead of at the >> point of creation/definition of the structure. What would stop the developer >> from writing the typo in their validation, as José did in his example? >> >> It seems to me like if the goal is to prevent typos then a struct would be >> the way to go. >> >> Kurtis Rainbolt-Greene <[email protected] >> <mailto:[email protected]>> schrieb am Mi. 30. Dez. 2020 um >> 09:29: >> Yes, but think of the valuable hours saved and the amount of code that won't >> have to be written. >> >> I mean even Valim's own example again has the typo. >> >> On Tue, Dec 29, 2020 at 11:58 PM Andrea Leopardi <[email protected] >> <mailto:[email protected]>> wrote: >> Considering how straightforward the code you showed is, and that for more >> complex scenarios we have libraries like nimble_options, I might be slightly >> hesitant to add this to core. >> >> Andrea >> >> On Wed, 30 Dec 2020 at 08:53, José Valim <[email protected] >> <mailto:[email protected]>> wrote: >> Hi everyone, >> >> I am working on a new project and yesterday I spent a couple hours on a bug >> due to a in a keyword list. In a nutshell, I was supposed to pass >> parenthesis: 10 as keywords to a function but I passed parentheses: 10. >> >> I have fixed the issue by adding the following code: >> >> for {k, _} <- keyword, k not in [:parentheses, :other_options], do: >> raise "unknown key #{inspect(k)} in #{inspect(keyword)}" >> >> The code is super straight-forward but I am wondering if we should add it to >> Elixir to promote said validation. What do you think? Any suggestions on >> where it should be defined and with which name? >> >> Thank you! >> >> >> -- >> 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/CAGnRm4J8_RG5eeCZSw_c75Q4y19YFt-ipdnTAEa1cE2GnvwjrQ%40mail.gmail.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4J8_RG5eeCZSw_c75Q4y19YFt-ipdnTAEa1cE2GnvwjrQ%40mail.gmail.com?utm_medium=email&utm_source=footer>. >> >> -- >> 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/CAM9Rf%2BJPu8tF2VzNB4beDqO9jc%2BF-SDE6u%3D724EZm9271jY2ug%40mail.gmail.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/CAM9Rf%2BJPu8tF2VzNB4beDqO9jc%2BF-SDE6u%3D724EZm9271jY2ug%40mail.gmail.com?utm_medium=email&utm_source=footer>. >> >> >> -- >> Kurtis Rainbolt-Greene, >> Software Developer & Founder of Difference Engineers >> 202-643-2263 >> >> -- >> 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/CAMhJPGiKh3uOaY2UNDFYu9x64n-mM7Sqf7iHU09QeAmfOY0mwQ%40mail.gmail.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/CAMhJPGiKh3uOaY2UNDFYu9x64n-mM7Sqf7iHU09QeAmfOY0mwQ%40mail.gmail.com?utm_medium=email&utm_source=footer>. >> -- >> >> _________________ >> Devon Estes >> +49 176 2356 4717 >> www.devonestes.com <http://www.devonestes.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 [email protected] >> <mailto:[email protected]>. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/CAGowJcg_DWYAQsys5f6Ad1nYket8be1Lsrmui8Uh%3DzEAKzWzTQ%40mail.gmail.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/CAGowJcg_DWYAQsys5f6Ad1nYket8be1Lsrmui8Uh%3DzEAKzWzTQ%40mail.gmail.com?utm_medium=email&utm_source=footer>. > > > -- > 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/5E7686D9-1DC6-4830-8C32-7FCAFFE6E706%40wojtekmach.pl > > <https://groups.google.com/d/msgid/elixir-lang-core/5E7686D9-1DC6-4830-8C32-7FCAFFE6E706%40wojtekmach.pl?utm_medium=email&utm_source=footer>. > > -- > 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/CAGnRm4%2B9YG1YwoK9JGAitzOzikOeo4dXCHyvu%3DjAU6SN1HRocw%40mail.gmail.com > > <https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4%2B9YG1YwoK9JGAitzOzikOeo4dXCHyvu%3DjAU6SN1HRocw%40mail.gmail.com?utm_medium=email&utm_source=footer>. -- 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/2A76D025-BF9B-45E1-B268-DD23753FEC6C%40wojtekmach.pl.
