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

Open
#777 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
r
Domain
cli

Research direction

Start at cli_progress_step() and reproduce the supplied examples, especially count_evals() and doesnt_work(). Trace when msg_done is evaluated at call time and completion; done should establish a consistent, documented evaluation model and cover the missing-y and repeated-evaluation cases with regression tests.

Written by the indexing model from the issue text.

Description

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]
Dominant language
R
Stars
726
Forks
94
Avg merge
3h 35m
Merged PRs (30d)
1

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from r-lib/cli

All issues in r-lib/cli

Similar issues

More R issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.