r-wasm / webr

The statistical language R compiled to WebAssembly via Emscripten, for use in web browsers and Node.
https://docs.r-wasm.org/webr/latest/
Other
805 stars 54 forks source link

`options(expressions=)` and the associated information about JS call stack size should be documented #374

Open JeremyPasco opened 4 months ago

JeremyPasco commented 4 months ago

Hi, I'm having errors on the following script with webr 0.2.2, which works fine on R standalone installation.

install.packages("gtsummary")
gtsummary::trial |> gtsummary::tbl_strata(
          strata = c(grade),
          .tbl_fun = ~ .x |> gtsummary::tbl_summary(by = trt) |> gtsummary::add_overall(last = T),
          .header = "**{strata}**, N = {n}"
         ) |> gtsummary::as_gt() |> gt::as_raw_html(F)

This procudes the following error:

Uncaught (in promise) Error: evaluation nested too deeply: infinite recursion / options(expressions=)? at captureR (blob:https://localhost:9000/1f4eb65b-40f0-468b-bb99-d2ee8c23bbd0:4727:15) at evalR (blob:https://localhost:9000/1f4eb65b-40f0-468b-bb99-d2ee8c23bbd0:4739:19) at PostMessageChannelWorker.dispatch (blob:https://localhost:9000/1f4eb65b-40f0-468b-bb99-d2ee8c23bbd0:4365:28) at PostMessageChannelWorker. (blob:https://localhost:9000/1f4eb65b-40f0-468b-bb99-d2ee8c23bbd0:3024:44)

Removing the following part solves the issue but I don't get why: |> gtsummary::add_overall(last = T)

With some variations, sometimes I get a different error: payload.ts:39 Uncaught (in promise) Error: In argument: tbl = switch(...). at captureR (blob:https://localhost:9000/b614354a-8ee1-4b1b-947f-f1c0a62bc18a:4727:15) at evalR (blob:https://localhost:9000/b614354a-8ee1-4b1b-947f-f1c0a62bc18a:4739:19) at PostMessageChannelWorker.dispatch (blob:https://localhost:9000/b614354a-8ee1-4b1b-947f-f1c0a62bc18a:4365:28) at PostMessageChannelWorker. (blob:https://localhost:9000/b614354a-8ee1-4b1b-947f-f1c0a62bc18a:3024:44)

georgestagg commented 4 months ago

WebR reduces the default value for options(expressions=) to 400, because call stack space in browser worker threads is limited and it helps catch deep evaluation errors with R conditions.

You may have some luck by first increasing the limit before running your script, with:

options(expressions = 1000)

or perhaps even higher. However, be aware that even if this works, it might not work in some browsers (often Safari) where the JavaScript call stack size is smaller than others.

JeremyPasco commented 4 months ago

Thanks. Just tried with 10K (Chrome and Edge on Windows 10 desktop) but got the same issue... so if I understand it correctly, this error could mean that I have reached the browser stack limit?

EDIT: I managed to make it work with 5K which is the R default value. But I wonder if there is an appropriate way to avoid increasing the stack and maximise chance it will work across all browsers? I have tried avoiding piping and storing intermediate states in variables but got exact same stack size.

georgestagg commented 4 months ago

But I wonder if there is an appropriate way to avoid increasing the stack and maximise chance it will work across all browsers?

There might not be much an end user can do, a lot will depend on the implementation details inside R packages and R itself, along with how much stack space is allocated internally to JS worker threads by browser engines such as Chromium and WebKit.

There should probably be more information in the webR documentation about this, and the options(expressions=) workaround for browsers that allocate enough stack. I will mark this thread with the documentation tag to remind me to come back to this and write some text for the docs.

JeremyPasco commented 4 months ago

Ouch, that is a tough outcome for some of my use cases. It might imply to rewrite from scratch some packages to reduce the stack size. The tricky part is that some scripts could work fine most of the time but would fail with some inputs because the stack size will increase a bit over the limit. I plan to run packages inner tests with expressions=400 (or even lower) to identify candidates to stack overflow.

PS: I noted the stack size is sometimes a bit larger when running a script under webr rather than R standalone.

Thanks for the enlightment!