How to Use the New R Promises Package

Estimated time:
time
min

<em><strong>Updated</strong>: October 24, 2022.</em> <strong>The long-awaited promises will be released soon!</strong> Being as impatient as I am when it comes to new technology, I decided to play with the currently available implementation of promises that Joe Cheng shared and presented recently in London at the EARL conference. From this article, you’ll get to know the upcoming <code class="highlighter-rouge">promises</code> package, how to use it, and how it is different from the already existing <code class="highlighter-rouge">future</code> package. Promises/Futures are a concept used in almost every major programming language. We’ve used Tasks in C#, Futures in Scala, and Promises in Javascript, and they all adhere to a common understanding of what a promise is. If you are not familiar with the concept of Promises, asynchronous tasks, or Futures, I advise you to take a long moment and dive into the topic. If you’d like to dive deeper and achieve a higher level of understanding, read about Continuation Monads in Haskell. We’ll be comparing the new <code class="highlighter-rouge">promises</code> package with the <code class="highlighter-rouge">future</code> package, which has been around for a while so I suggest you take a look at the <a href="https://cran.r-project.org/web/packages/future/vignettes/future-1-overview.html">future package overview</a> first if you haven’t used it before. Citing Joe Cheng, our aim is to: <ol><li>Execute long-running code asynchronously on a separate thread.</li><li>Be able to do something with the result (if success) or error (if failure), when the task completes, back on the main R thread.</li></ol> A promise object represents the eventual result of an async task. A promise is an R6 object that knows: <ol><li>Whether the task is running, succeeded, or failed</li><li>The result (if succeeded) or error (if failed)</li></ol> <strong>Table of contents</strong>: <ul><li><a href="#future">Using the R Future package</a></li><li><a href="#promises">R Promises - How to Get Started</a></li><li><a href="#summary">Summing up R Promises</a></li></ul> <hr /> <h2 id="future">Using the R Future package</h2> Without further ado, let’s get our hands on the code! You should be able to just copy-paste code into RStudio and run it. R is single-threaded. This means that users cannot interact with your shiny app if there is a long-running task being executed on the server. Let’s take a look at an example: <pre><code class="language-r">longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- longRunningFunction(1) b &lt;- longRunningFunction(2) print(paste0("User interaction - ", Sys.time() - start_time)) c &lt;- longRunningFunction(10) print(a) print(b) sumAC &lt;- a + c sumBC &lt;- b + c print(paste0("User interaction - ", Sys.time() - start_time)) print(sumAC + sumBC) print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16304" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b7d711303d514718a20766_a5c4e6dc_1-4.webp" alt="Image 1 - R Promises Output (1)" width="978" height="606" /> Image 1 - R Promises Output (1) We’ll use a simplified version of user interaction while there are some additional computations happening on the server. Let’s assume that we can’t just put all the computations in a separate block of code and just run it separately using the <code class="highlighter-rouge">future</code> package. There are many cases when it is very difficult or even almost impossible to just gather all computations and run them elsewhere as one big long block of code. The user cannot interact with the app for 10 seconds until the computations are finished and then the user has to wait another 5 seconds for the next interaction. This is not a place where we would like to be. User interactions should be as fast as possible and the user shouldn’t have to wait if it is not required. Let’s fix that using R <code class="highlighter-rouge">future</code> package that we know. You'll have to install it first: <pre><code class="language-r">install.packages("future")</code></pre> Onto the code now: <pre><code class="language-r">library(future) plan(multisession) <br>longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(1)) b &lt;- future(longRunningFunction(2)) print(paste0("User interaction - ", Sys.time() - start_time)) c &lt;- future(longRunningFunction(10)) print(value(a)) print(value(b)) sumAC &lt;- value(a) + value(c) sumBC &lt;- value(b) + value(c) print(paste0("User interaction - ", Sys.time() - start_time)) print(sumAC + sumBC) print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16306" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270709c5dda5a10df1dfd_2-4.webp" alt="Image 2 - R Promises Output (2)" width="950" height="612" /> Image 2 - R Promises Output (2) Nice, now the first user interaction can happen in parallel! But the second interaction is still blocked - we have to wait for the values, to print their sum. In order to fix that we’d like to chain the computation into the summing function instead of waiting synchronously for the result. We can’t do those using pure futures though (assuming we can’t just put all these computations in one single block of code and run it in parallel). Ideally, we’d like to be able to write code similar to the one below: <pre><code class="language-r">library(future) plan(multisession) <br>longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(1)) b &lt;- future(longRunningFunction(2)) print(paste0("User interaction - ", Sys.time() - start_time)) c &lt;- future(longRunningFunction(10)) future(print(value(a))) future(print(value(b))) sumAC &lt;- future(value(a) + value(c)) sumBC &lt;- future(value(b) + value(c)) print(paste0("User interaction - ", Sys.time() - start_time)) print(future(value(sumAC) + value(sumBC))) print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16308" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270715c15db9346e7622e_3-4.webp" alt="Image 3 - R Promises Output (3)" width="1796" height="750" /> Image 3 - R Promises Output (3) Unfortunately <code class="highlighter-rouge">future</code> package won’t allow us to do that. <h2 id="promises">R Promises - How to Get Started</h2> What we can do, is use the <a href="https://github.com/rstudio/promises" target="_blank" rel="noopener noreferrer">promises</a> package from RStudio! <pre><code class="language-r">devtools::install_github("rstudio/promises")</code></pre> <hr /> <strong>Let’s play with the promises!</strong> I simplified our example to let us focus on using promises first: <pre><code class="language-r">library(future) plan(multisession) library(tibble) <br>longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(tibble(number = 1:100))) print(value(a)) print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16310" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b27071dd103fc6f102dcd1_4-3.webp" alt="Image 4 - R Promises Output (4)" width="942" height="646" /> Image 4 - R Promises Output (4) We’d like to chain the result of <code class="highlighter-rouge">longRunningFunction</code> to a print function so that once the <code class="highlighter-rouge">longRunningFunction</code> is finished, its results are printed. We can achieve that by using the %…&gt;% operator. It works like the very popular <a href="https://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html" target="_blank" rel="noopener noreferrer">%&gt;% operator from magrittr</a>. Think of <code class="highlighter-rouge">%...&gt;%</code> as “sometime in the future, once I have the result of the operation, pass the result to the next function”. The three dots symbolize the fact that we have to wait and that the result will be passed in the future, it’s not happening now. <pre><code class="language-r">library(future) plan(multisession) library(promises) library(tibble) library(dplyr) <br>longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(tibble(number = 1:100))) a %&gt;%  print() print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16312" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b27077580c4700e3569724_5-3.webp" alt="Image 5 - R Promises Output (5)" width="1688" height="852" /> Image 5 - R Promises Output (5) Pure magic. But what if I want to filter the result first and then print the processed data? Just keep on chaining: <pre><code class="language-r">library(future) plan(multisession) library(promises) library(tibble) library(dplyr) <br>longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(tibble(number = 1:100))) a %...&gt;%  filter(., number %% 2 == 1) %...&gt;%  sum() %...&gt;%  print() print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16314" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b2707c5f867c2801dc6249_6-2.webp" alt="Image 6 - R Promises Output (6)" width="934" height="306" /> Image 6 - R Promises Output (6) Neat. But, how can I print the result of filtering and pass it to the <code class="highlighter-rouge">sum</code> function? There is a tee operator, the same as the one magrittr provides (but one that operates on a promise). It will pass the result of the function to the next function. If you chain it further, it will not pass the result of <code class="highlighter-rouge">print()</code> function but the previous results. Think of it as splitting a railway, printing the value on a side track and ending the run, then getting back to the main track: <pre><code class="language-r">library(future) plan(multisession) library(promises) library(tibble) library(dplyr) <br>longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(tibble(number = 1:100))) a %...&gt;%  filter(number %% 2 == 1) %...T&gt;%  print() %...&gt;%  sum() %...&gt;%  print() print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16316" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b270956402741d1b1559ac_7-3.webp" alt="Image 7 - R Promises Output (7)" width="950" height="814" /> Image 7 - R Promises Output (7) What about errors? They are being thrown somewhere else than in the main thread, how can I catch them? You guessed it - there is an operator for that as well. Use <code class="highlighter-rouge">%...!%</code> to handle errors: <pre><code class="language-r">library(future) plan(multisession) library(promises) library(tibble) library(dplyr) <br>longRunningFunction &lt;- function(value) {  stop("ERROR")  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(tibble(number = 1:100))) a %...&gt;%  filter(number %% 2 == 1) %...T&gt;%  print() %...&gt;%  sum() %...&gt;%  print() %...!%  (function(error) {    print(paste("Unexpected error: ", error$message))  }) print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16318" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b2709664958610e6dcb04f_8-3.webp" alt="Image 8 - R Promises Output (8)" width="938" height="442" /> Image 8 - R Promises Output (8) But in our example, we’re not just chaining one computation. There is a <code class="highlighter-rouge">longRunningFunction</code> call that eventually returns 1 and another one that eventually returns 2. We need to somehow join the two. Once both of them are ready, we’d like to use them and return the sum. We can use <code class="highlighter-rouge">promise_all</code> function to achieve that. It takes a list of promises as an argument and returns a promise that eventually resolves to a list of results of each of the promises. Perfect. We know the tools that we can use to chain asynchronous functions. Let’s use them in our example then: <pre><code class="language-r">library(future) plan(multisession) library(promises) library(purrr) <br>longRunningFunction &lt;- function(value) {  Sys.sleep(5)  return(value) } <br>start_time &lt;- Sys.time() a &lt;- future(longRunningFunction(1)) b &lt;- future(longRunningFunction(2)) print(paste0("User interaction - ", Sys.time() - start_time)) c &lt;- future(longRunningFunction(10)) a %...&gt;% print() b %...&gt;% print() sumAC &lt;- promise_all(a, c) %...&gt;% reduce(`+`) sumBC &lt;- promise_all(b, c) %...&gt;% reduce(`+`) print(paste0("User interaction - ", Sys.time() - start_time)) promise_all(sumAC, sumBC) %...&gt;% reduce(`+`) %...&gt;% print() print(paste0("User interaction - ", Sys.time() - start_time))</code></pre> <img class="size-full wp-image-16320" src="https://webflow-prod-assets.s3.amazonaws.com/6525256482c9e9a06c7a9d3c%2F65b2706e5c9f924b369f2f91_9-2.webp" alt="Image 9 - R Promises Output (9)" width="952" height="612" /> Image 9 - R Promises Output (9) A task for you - in line <code class="highlighter-rouge">sumAC &lt;- promise_all(a, c) %...&gt;% reduce(</code>+<code class="highlighter-rouge">)</code>, print the list of values from promises <code class="highlighter-rouge">a</code> and <code class="highlighter-rouge">c</code> before they are summed up. <hr /> <h2 id="summary">Summing up R Promises</h2> And there you have it - everything that the upcoming R promises package has to offer. We're looking forward to the release and hope this article got you excited about the concept of promises as well. In the meantime, feel free to refer to the links listed below. <strong>A handful of useful information:</strong> <p style="padding-left: 40px;">[1] There is support for promises implemented in shiny but neither CRAN nor GitHub master branch versions of Shiny support promises. Until support is merged, you’ll have to install from the async branch:</p> <figure class="highlight" style="padding-left: 40px;"> <pre style="padding-left: 40px;"><code class="language-r" data-lang="r"><span class="n">devtools</span><span class="o">::</span><span class="n">install_github</span><span class="p">(</span><span class="s2">"rstudio/shiny@async"</span><span class="p">)</span></code></pre> </figure> <p style="padding-left: 40px;">[2] Beta-quality code at <a href="https://github.com/rstudio/promises">GitHub</a></p> <p style="padding-left: 40px;">[3] Early drafts of docs temporarily hosted at <a href="https://medium.com/@joe.cheng">Joe Cheng's Medium</a></p> <p style="padding-left: 40px;">[4] The plan is to release everything on CRAN by end of this year.</p> <strong>I hope you have as much fun playing with the promises as I did!</strong> I’m planning to play with shiny support for promises next.

Contact us!
Damian's Avatar
Damian Rodziewicz
Head of Sales
r
tutorials