Skip to content

cli_progress_step() : evaluate msg_done twice (unexpected mix of eager and lazy) ? #777

@smartiing

Description

@smartiing

Hi, and thanks for the amazing work on the cli package!

What puzzles me is that the behavior seems in between two expected paradigms:

  • Either the interpolation is eager (evaluated at the moment of the function call), which would make sense to avoid surprises and ensure the message is fixed and reproducible.
  • Or the interpolation is lazy, evaluated only when the message is actually displayed, which also makes sense, e.g., to reflect the state of a variable when exiting a function.

But in fact msg_done is being evaluated twice.

  • Any variable use in interpolation must exist at the time the function is called (otherwise you get an error),
  • yet its value is not captured at that moment and it can still be updated before the message is shown.

Is this the intended behaviour ?

Thanks a lot in advance!

library(cli)

works_if_exists_before = function() {
  x = "foo"
  y = "bar"
  
  cli_progress_step(
    msg = "I show {x} at first",
    msg_done = "And {y} at the end"
  )
  
  Sys.sleep(1)
}

works_if_exists_before()
#> ℹ I show foo at first✔ And bar at the end [1.1s]


works_with_dummy_before = function() {
  x = "foo"
  y = ""
  
  cli_progress_step(
    msg = "I show {x} at first",
    msg_done = "And {y} at the end"
  )
  
  y = "bar"
  
  Sys.sleep(1)
}

works_with_dummy_before()
#> ℹ I show foo at first✔ And bar at the end [1.1s]


doesnt_work = function() {
  x = "foo"
  
  cli_progress_step(
    msg = "I show {x} at first",
    msg_done = "And {y} at the end"
  )
  
  y = "bar"
  Sys.sleep(1)
}

doesnt_work()
#> Error in "\"id\" %in% names(args)": ! Could not evaluate cli `{}` expression: `y`.
#> Caused by error in `eval(expr, envir = envir)`:
#> ! object 'y' not found
#> Error in c("(function (e) ", "{"): ! Error in a deferred `on.exit()` clause
#> Caused by error in `"id" %in% names(args)`:
#> ! Could not evaluate cli `{}` expression: `y`.
#> Caused by error in `eval(expr, envir = envir)`:
#> ! object 'y' not found

evaluated = function() {
  value = "once"
  function() {
    if (value == "once") {
      value <<- "twice"
      return("once")
    } else if (value == "twice") {
      value <<- "more than twice"
      return("twice")
    } else {
      return("more than twice")
    }
  }
}

count_evals = function() {
  f = evaluated()
  cli_progress_step(
    msg = "msg",
    msg_done = "evaluated {f()}"
  )
}

count_evals()
#> ℹ msg✔ evaluated twice [6ms]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions