5 Comments

In general, this family of patterns really speaks to me. I feel like I run into it fairly often. That said, I think a lot of times I'm really running into the "three functions in a trench coat" problem. It might be good to emphasize when to split things earlier on (although I also see there's a whole chapter for that).

For the name: Maybe emphasize the helpers (both in 13 and 11), something like "Reduce argument clutter with an options helper" and "Extract strategies into options helpers"? I'm not sure that's catchier, but "an options object" sounds like it could just be a list (which is how I read it at first), and those just feel like hidden arguments (eg, the `params` argument in `xgboost::xgboost()`, which requires you to read a separate website to find out what you can set).

From 13: "You could also implement the same strategy using `if` or S7 generic functions, depending on your needs." When would you switch from `switch` to S7 generics?

Expand full comment
author

Thanks for feedback! There will eventually be a whole chapter on if vs switch vs generics: https://github.com/tidyverse/design/issues/163.

Expand full comment

Also interested in that last question.

Expand full comment
Dec 21, 2023·edited Dec 21, 2023

You've mentioned a downside of the enumeration strategy being that it forces a default value, and you have another chapter about not giving required arguments a default value.

If I have a required argument that I'd like to use enumeration for but I don't want the argument to choose either option by default, is it poor design to set the default to NULL and handle the NULL value by raising an error?

EDIT: I have discovered that the NULL value in c(NULL, ...) default parameter is dropped upon function call. So I rephrase my question with an alternative:

In order to use the enumeration strategy but avoid providing a default choice, would it be poor design to set the default to some value that will be immediately handled by raising an error?

Expand full comment
author

As I see, it there are two choices, each of which has drawbacks:

* Your suggestion, which is basically `arg = c("error", "a", "b", "c")`. This is a bit misleading because by providing a default value you suggest that it's an optional argument, not required.

* Alternatively, you could leave the default empty which means that the possible values won't be clearly indicated in the function signature, but it does make it clear that the argument is required.

Overall, I think I'd lean towards the second option, especially since in the future we could make `arg_match()` give a better error here.

Expand full comment