1<%@meta language="R-vignette" content="--------------------------------
2%\VignetteIndexEntry{A Future for R: Text and Message Output}
3%\VignetteAuthor{Henrik Bengtsson}
4%\VignetteKeyword{R}
5%\VignetteKeyword{package}
6%\VignetteKeyword{vignette}
7%\VignetteKeyword{future}
8%\VignetteKeyword{promise}
9%\VignetteKeyword{output}
10%\VignetteKeyword{standard output}
11%\VignetteKeyword{stdout}
12%\VignetteKeyword{standard error}
13%\VignetteKeyword{stderr}
14%\VignetteKeyword{message}
15%\VignetteKeyword{condition}
16%\VignetteEngine{R.rsp::rsp}
17%\VignetteTangle{FALSE}
18--------------------------------------------------------------------"%>
19# <%@meta name="title"%>
20
21Futures will _relay_ output produced by functions such as `cat()`, `print()` and `str()`.  More specifically, output sent to the standard output (stdout) while a future is evaluated will be captured and _re-outputted ("relayed") when the value of the future is queried_.  Messages produced by `message()`, which formally are R conditions are also captured and resignaled ("relayed") as messages in the main R session.  Importantly, this works identically regardless of future backend used.
22
23For simplicitly, lets start with an illustration on how standard output ("stdout") is captured and relayed:
24
25```r
26> library("future")
27> plan(multisession)
28
29> fa <- future({ cat("Hello world!\n"); print(1:3); 42L })
30> fb <- future({ str(iris); summary(iris) })
31
32> a <- value(fa)
33Hello world!
34[1] 1 2 3
35> b <- value(fb)
36'data.frame':	150 obs. of  5 variables:
37 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
38 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
39 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
40 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
41 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
42
43> a
44[1] 42
45> b
46  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species
47 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100   setosa    :50
48 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300   versicolor:50
49 Median :5.800   Median :3.000   Median :4.350   Median :1.300   virginica :50
50 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199
51 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800
52 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500
53```
54
55Note that the captured standard output (stdout) will be relayed _each_ time `value()` is called, e.g.
56```r
57> a <- value(fa)
58Hello world!
59[1] 1 2 3
60
61> a <- value(fa)
62Hello world!
63[1] 1 2 3
64```
65
66Output is relayed the same way when using future assignments (`%<-%`).  For example,
67
68```r
69> library("future")
70> plan(multisession)
71
72> a %<-% { cat("Hello world!\n"); print(1:3); 42L }
73> b %<-% { str(iris); summary(iris) }
74
75> a
76Hello world!
77[1] 1 2 3
78[1] 42
79> b
80'data.frame':	150 obs. of  5 variables:
81 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
82 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
83 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
84 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
85 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
86  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species
87 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100   setosa    :50
88 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300   versicolor:50
89 Median :5.800   Median :3.000   Median :4.350   Median :1.300   virginica :50
90 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199
91 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800
92 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500
93```
94
95Note how the captured output is relayed followed by the printing of the value.  Also, since the future value is only queried once when using future assignments, or more specifically when using promises, the output is only relayed once.  For example, querying `a` again will only print its value, because it is now a regular R object:
96```r
97> a
98[1] 42
99> a
100[1] 42
101```
102
103Next, lets see what happens if we use `message()` to produce output:
104
105```r
106> library("future")
107> plan(multisession)
108> fa <- future({ message("Hello world!"); 42L })
109> value(fa)
110Hello world!
111[1] 42
112```
113
114Note that contrary to the captured stdout, which is captured as one single block output, messages are conditions that are captured separately.  Unfortunately, it is _not_ possible to preserve the ordering of interweaved stdout and message output.  When using futures, stdout output will always be relayed first followed by each of the individual conditions captured.  For example,
115
116
117```r
118> library("future")
119> plan(multisession)
120> fa <- future({ message("Hello"); print(1:3); message("world!"); cat("ping\n"); 42L })
121> value(fa)
122[1] 1 2 3   ## <= stdout as a single ...
123ping        ## <= ... block of output
124Hello       ## <= 1st message
125world!      ## <= 2nd message
126[1] 42
127```
128
129
130## Future frontends
131
132The output is relayed automatically also when using frontends such as [future.apply] or [foreach] with [doFuture].  Again, it works with any future backend.  For example,
133
134```r
135> library("future.apply")
136> plan(future.callr::callr)
137
138> y <- future_lapply(1:3, FUN = function(x) { cat("x =", x, "\n"); message("x : ", x); sqrt(x) })
139x = 1
140x = 2
141x = 3
142x : 1  ## <= 1st message
143x : 2  ## <= 2nd message
144x : 3  ## <= 3rd message
145
146> str(y)
147List of 3
148 $ : num 1
149 $ : num 1.41
150 $ : num 1.73
151```
152
153Equivalently,
154
155```r
156> library("doFuture")
157> registerDoFuture()
158> plan(future.callr::callr)
159
160> y <- foreach(x = 1:3) %dopar% { cat("x =", x, "\n");  message("x : ", x); sqrt(x) }
161x = 1
162x = 2
163x = 3
164x : 1  ## <= 1st message
165x : 2  ## <= 2nd message
166x : 3  ## <= 3rd message
167
168> str(y)
169List of 3
170 $ : num 1
171 $ : num 1.41
172 $ : num 1.73
173```
174
175
176## Capturing output
177
178To capture the output produced by futures, use `capture.output()` as you would do when capturing output elsewhere in R.  For example,
179
180```r
181> library("future")
182> fa <- future({ cat("Hello world!\n"); print(1:3); 42L })
183> stdout <- capture.output(a <- value(fa))
184> stdout
185[1] "Hello world!" "[1] 1 2 3"
186> a
187[1] 42
188```
189
190
191## Suppressing messages
192
193```r
194> library("future")
195> plan(multisession)
196> fa <- future({ message("Hello"); print(1:3); message("world!"); cat("ping\n"); 42L })
197> suppressMessages(a <- value(fa))
198[1] 1 2 3
199ping
200> a
201[1] 42
202```
203
204
205## Known limitations
206
207It is only the standard output that is relayed.  It is _not possible_ to relay output send to the standard error (stderr), e.g. output by `cat(..., file = stderr())` will be lost.  This is due to a [limitation in R](https://github.com/HenrikBengtsson/Wishlist-for-R/issues/55), preventing us from capturing stderr in a reliable way, particularity across all backends.  However, note that the captured messages by `message()` are outputted to stderr (as expected) when resignaled/relayed.
208
209
210[foreach]: https://cran.r-project.org/package=foreach
211[future]: https://cran.r-project.org/package=future
212[future.apply]: https://cran.r-project.org/package=future.apply
213[doFuture]: https://cran.r-project.org/package=doFuture
214[globals]: https://cran.r-project.org/package=globals
215[listenv]: https://cran.r-project.org/package=listenv
216