-
Notifications
You must be signed in to change notification settings - Fork 53
/
out-invisible.qmd
85 lines (62 loc) · 2.05 KB
/
out-invisible.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
# Side-effect functions should return invisibly {#sec-out-invisible}
```{r}
#| include = FALSE
source("common.R")
```
## What's the pattern?
If a function is called primarily for its side-effects, it should invisibly return a useful output.
If there's no obvious output, return the first argument.
This makes it possible to use the function with in a pipeline.
## What are some examples?
```{r}
#| eval = FALSE,
#| include = FALSE
source("fun_def.R")
pkg_funs("base") %>%
funs_body_keep(has_call, "invisible") %>%
discard(~ grepl("print", .x$name))
```
- `print(x)` invisibly returns the printed object.
- `x <- y` invisible returns `y`.
This is what makes it possible to chain together multiple assignments `x <- y <- z <- 1`
- `readr::write_csv()` invisibly returns the data frame that was saved.
- `purrr::walk()` invisibly returns the vector iterated over.
- `fs:file_copy(from, to)` returns `to`
- `options()` and `par()` invisibly return the previous value so you can reset with `on.exit()`.
## Why is it important?
Invisibly returning the first argument allows to call the function mid-pipe for its side-effects while allow the primary data to continue flowing through the pipe.
This is useful for generating intermediate diagnostics, or for saving multiple output formats.
```{r}
library(dplyr, warn.conflicts = FALSE)
library(tibble)
mtcars %>%
as_tibble() %>%
dplyr::filter(cyl == 6) %>%
print() %>%
group_by(vs) %>%
summarise(mpg = mean(mpg))
```
```{r}
library(readr)
mtcars %>%
write_csv("mtcars.csv") %>%
write_tsv("mtcars.tsv")
unlink(c("mtcars.csv", "mtcars.tsv"))
```
```{r}
library(fs)
paths <- file_temp() %>%
dir_create() %>%
path(letters[1:5]) %>%
file_create()
paths
```
Functions that modify some global state, like `options()` or `par()`, should return the *previous* value of the variables.
This, in combination with compound argument pattern from @sec-implicit-strategies, makes it possible to easily reset the effect of the change:
```{r}
x <- runif(1)
old <- options(digits = 3)
x
options(old)
x
```