-
Notifications
You must be signed in to change notification settings - Fork 54
/
Copy pathdots-prefix.qmd
87 lines (61 loc) · 2.51 KB
/
dots-prefix.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# Dot prefix {#sec-dots-prefix}
```{r}
#| include = FALSE
source("common.R")
```
## What's the pattern?
When using `...` to create a data structure, or when passing `...` to a user-supplied function, add a `.` prefix to all named arguments.
This reduces (but does not eliminate) the chances of matching an argument at the wrong level.
Additionally, you should always provide some mechanism that allows you to escape and use that name if needed.
```{r}
#| label = "setup"
library(purrr)
```
(Not important if you ignore names: e.g. `cat()`.)
## What are some examples?
Look at the arguments to some functions in purrr:
```{r}
args(map)
args(reduce)
args(detect)
```
Notice that all named arguments start with `.`.
This reduces the chance that you will incorrectly match an argument to `map()`, rather than to an argument of `.f`.
Obviously it can't eliminate it.
Escape mechanism is the anonymous function.
Little easier to access in `purrr::map()` since you can create with `~`, which is much less typing than `function() {}`.
For example, imagine you want to...
Example: https://jennybc.github.io/purrr-tutorial/ls02_map-extraction-advanced.html#list_inside_a_data_frame
## Case study: dplyr verbs
```{r}
args(dplyr::filter)
args(dplyr::group_by)
```
Escape hatch is `:=`.
Ooops:
```{r}
args(dplyr::left_join)
```
## Other approaches in base R
Base R uses two alternative methods: uppercase and `_` prefix.
The apply family tends to use uppercase function names for the same reason.
Unfortunately the functions are a little inconsistent which makes it hard to see this pattern.
I think a dot prefix is better because it's easier to type (you don't have to hold down the shift-key with one finger).
```{r}
args(lapply)
args(sapply)
args(apply)
args(mapply)
args(tapply)
```
`Reduce()` and friends avoid the problem altogether by not accepting `...`, and requiring that the user creates anonymous functions.
But this is verbose, particularly without shortcuts to create functions.
`transform()` goes a step further and uses an non-syntactic variable name.
```{r}
args(transform)
```
Using a non-syntactic variable names means that it must always be surrounded in `` ` ``.
This means that a user is even less likely to use it that with `.`, but it increases friction when writing the function.
In my opinion, this trade-off is not worth it.
## What are the exceptions?
- `tryCatch()`: the names give classes so, as long as you don't create a condition class called `expr` or `finally` (which would be weird!) you don't need to worry about matches.