Get value from R fullfilled promise
Asked Answered
I

4

6

I read many articles about R promises (including this) and still don't get it.

See code:

library(future)
library(promises)
plan(multiprocess)

read.csv.async <- function(file, header = TRUE, stringsAsFactors = FALSE) {
  future({
    read.csv(file, header = header, stringsAsFactors = stringsAsFactors)
  })
}

df_promise <- read.csv.async("https://rstudio.github.io/promises/data.csv")

df_promise %...>% filter(state == "NY")

df_filtered_promise <- df_promise %...>% filter(state == "NY")

df_filtered_promise

class(df_filtered_promise)

Output:

> read.csv.async <- function(file, header = TRUE, stringsAsFactors = FALSE) {
+   future({
+     read.csv(file, header = header, stringsAsFactors = stringsAsFactors)
+   })
+ }
> 
> df_promise <- read.csv.async("https://rstudio.github.io/promises/data.csv")
> 
> df_promise %...>% filter(state == "NY")
> 
> df_filtered_promise <- df_promise %...>% filter(state == "NY")
> 
> df_filtered_promise
<Promise [pending]>
> df_filtered_promise
<Promise [fulfilled: data.frame]>
> class(df_filtered_promise)
[1] "promise"

Why fullfilled promise doesn't return its value? How can I extract data frame in my case?

Invar answered 25/7, 2019 at 0:7 Comment(5)
@r2evans I don't ask how future works, but promises.Invar
Sorry, I thought they were close enough, but you're right, I rushed.Extern
the code wont work for me:> read.csv.async <- function(file, header = TRUE, stringsAsFactors = FALSE) { + future({ + read.csv(file, header = header, stringsAsFactors = stringsAsFactors) + }) + } > df_promise <- read.csv.async("rstudio.github.io/promises/data.csv") > df_promise %...>% filter(state == "NY") Error in df_promise %...>% filter(state == "NY") : could not find function "%...>%"Aeroplane
@DanielFischer just add library(promises)Invar
I find their documentation a little incomplete: I can, for instance, do df_promise %...>% print() and it will print it out, but I don't want it printed, I want it realized/gathered. I wonder if the intent for promises is really not at all user-interactive so much as shiny (for which it works well).Extern
B
9

There is a way to do this, but before I tell you, I would advise you not to use promises for interactive or scripting use, probably. Synchronous programming is more convenient than asynchronous, and you should only do the latter if it's very important not to tie up the main R thread (as is the case with Shiny if you want to keep apps responsive while long operations run).

If you choose to use future, try to get away with not chaining any %...>% operations after it, and then you can simply use future::value as Daniel Fischer said.

If you do decide to fully use promises, and it's important to you to extract the value out into a regular variable, then you can accomplish this via side effects, like this super-assign:

df_filtered <- NULL
df_filtered_promise %...>% { df_filtered <<- . }

This will cause the df_filtered variable to be set to the result of df_filtered_promise at some point in the future. (It will never be assigned in the case of error, though.)

This generally ought not be done in Shiny, as you usually want to keep things wrapped in promises all the way to the end of the computation so Shiny can keep track of what outputs/observers are waiting on what operations.

Barrator answered 26/7, 2019 at 5:7 Comment(1)
> "I would advise you not to use promises for interactive or scripting use, probably." The complexity of promises is indeed daunting and I haven't chosen to use it in a script for 'fun.' The RLesur/crrri package relies on promises and if you want to extract the html results in a script, you need to do something like this (I landed here because I was desperate to return/collect my crri/promises html results without using a super/global assign). Looks like that's the best we can do for now.Trainband
A
5

df <- environment (promise_object[["then"]])[["private"]][["value"]] is what you are looking for.

Promise object stores data and properties in a nested list format and that list is part of the environment object.

Auspice answered 4/12, 2020 at 5:48 Comment(1)
Hi and welcome to Stack Overflow! Please take the tour. Thanks for answering but can you also add an explanation on how your code solves the issue? Check the help center for info on how to format code.Weisshorn
H
0
promise %>% 
  {.$then} %>% 
  environment %>% 
  {.$private$value}

You can try this.

If promise is not fullfilled, this will return NULL.


e.g.

seq(3) %>% promises::promise_map(\ (a) a+1) -> promise

(\ (promise) promise %>% 
    {.$then} %>% environment %>% 
    {while (.$private$state != "fulfilled") {
        
        message (.$private$state," ..."); Sys.sleep(1)
        }; .$private$value} %>% 
    
{.}) (promise)

If you submit these code to console once, it will prnding ... forever; but if you submit these code one by one, it will return the result. So if you want to get the result out of the promise box in a script, you will fail.

So how can we use the value inside that promise box ? The answer (may be only one) is use then or %...>% pipe. And if you have many value in several promise box, you can do something like this:

seq(3) %>% promises::promise_map(\ (a) a+1) -> promise0
seq(1) %>% promises::promise_map(\ (a) a+1) -> promise1

promise0 %>% 
    promises::then (\ (a) promise1 %>% 
        promises::then (\ (b) (a %>% unlist) - (b %>% unlist))) %>% 
    promises::then (\ (x) x %T>% print %>% class %>% print)

Or clearly, use promise_all:

seq(3) %>% promises::promise_map (\ (a) a+1) -> promise0
seq(1) %>% promises::promise_map (\ (a) a+1) -> promise1

promise_ab = promises::promise_all (a = promise0, b = promise1)

promise_ab %>% 
    promises::then (\ (x) (x$a %>% unlist) - (x$b %>% unlist)) %>% 
    promises::then (\ (x) x %T>% print %>% class %>% print)

(For me, I like the future more ... )

Harden answered 26/2, 2024 at 10:13 Comment(0)
A
-2

you have to use value function:

value(df_filtered_promise)
Aeroplane answered 25/7, 2019 at 0:38 Comment(1)
No: > future::value(df_filtered_promise) Error in UseMethod("value") : no applicable method for 'value' applied to an object of class "promise"Invar

© 2022 - 2025 — McMap. All rights reserved.