The issue is that for take!, I can see two semantics: 1. The map/keyword must have all of the given keys 2. The map/keyword must have at most the given keys
And I think 1) makes more sense intuitively. :( On Wed, Dec 30, 2020 at 11:48 AM Wojtek Mach <[email protected]> wrote: > 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]> 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]> 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]> 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]> >>> 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]> 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]. >>>>> 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]. >>>> 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]. >>> 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 >> >> >> -- >> 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/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]. >> 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]. > 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 > <https://groups.google.com/d/msgid/elixir-lang-core/2A76D025-BF9B-45E1-B268-DD23753FEC6C%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]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAGnRm4Jx0-0xU76qaury3k5P8WuKjNRj8xUKj1Cz8a0YyuX%2BMA%40mail.gmail.com.
