[R-pkg-devel] [External] Re: Subset assignment rule changes in R-devel

iuke-tier@ey m@iii@g oii uiow@@edu iuke-tier@ey m@iii@g oii uiow@@edu
Tue Dec 16 18:12:33 CET 2025


On Mon, 15 Dec 2025, Konrad Rudolph wrote:

> Hi Luke,
> Thanks for the sleuthing and the suggested workaround. Unfortunately the
> actual package code is a bit more complex, and surprisingly that breaks the
> workaround via compiler::compile() (it fails just like the interpreted
> version). In particular, my code is trying to guard against the (very
> unlikely) scenario in which the calling code has redefined (or undefined)
> `<-`, by explicitly qualifying it as base::`<-`():

This doesn't protect you against redefining or undefining `<-`. It
does protect against masking the base definition with one in an
environment frame. But you could check for that and throw an error if
it has happened. Then you could keep the rest of your code more sane.

> f <- function (value) {
>      if (missing(value)) {
>          evalq(x[1L, ], .GlobalEnv)
>      } else {
>          assign_expr <- substitute(base::`<-`(x[1L, ], value), list(value =
> value))
>          cmp_assign_expr <- compiler::compile(assign_expr)
>          eval(cmp_assign_expr, .GlobalEnv)
>      }
> }

I committed a small change to R-devel in r89182 that makes handling of
the internal `*tmp*` variable a bit more robust, so your examples
should no longer throw errors.

> (Incidentally I agree that this could be written much simpler, without
> eval(); however, the purpose of the package is to provide a generic
> mechanism to allow defining aliases to complex expressions via NSE; e.g. you
> might write `ax := x[1L, ]`, and `ax` would henceforth operate as an alias
> for that expression.)

Not sure this is a realistic goal but good luck with that.

Best,

luke

> 
> Cheers,
> Konrad
> 
> 
> On Mon, 15 Dec 2025 at 04:26, <luke-tierney using uiowa.edu> wrote:
>       On Sun, 14 Dec 2025, Simon Urbanek wrote:
>
>       > Konrad,
>       >
>       > I can reproduce this is current R-devel on any platform, so
>       this should be very easy to reproduce, it is not OS-specific at
>       all - all R-devel checks will flag it eventually. I would guess
>       this is from:
>       >
>       > r89121 | luke | 2025-12-09 04:28:24 +1300 (Tue, 09 Dec 2025) |
>       3 lines
>       >
>       > Mark values returned by active binding functions as not
>       mutable to
>       > prevent unintended mutation in complex assignments.
>       >
>       > So it looks like it is intentional. May need some discussion
>       on whether this requires some re-design of your package to make
>       it safer or if it is a valid use-cases that may need further
>       consideration.
>
>       Looks like it is a side effect of that bug fix that it is waking
>       up a
>       misfeature of the interpreted complex assignment code. The
>       compiled
>       version of the complex assignment code is cleaner and does not
>       have
>       this issue, so you could use
>
>       f <- function (value) {
>            if (missing(value)) {
>                evalq(x[1L, ], .GlobalEnv)
>            } else {
>                assign_expr <- substitute(x[1L, ] <- value, list(value
>       = value))
>                cmp_assign_expr <- compiler::compile(assign_expr)
>                eval(cmp_assign_expr, .GlobalEnv)
>            }
>       }
>
>       Depending on how close this is to what you are really doing
>       Konrad,
>       you can also use .GlobalEnv$x and avoid eval():
>
>       f <- function (value) {
>            if (missing(value))
>                .GlobalEnv$x[1L, ]
>            else
>                .GlobalEnv$x[1L, ] <- value
>       }
>
>       I'll see if I can figure out what is going on in the interpreted
>       assignment code.
>
>       Best,
>
>       luke
>
>       >
>       > Cheers,
>       > Simon
>       >
>       >
>       >> On 15 Dec 2025, at 10:50, Konrad Rudolph
>       <konrad.rudolph using gmail.com> wrote:
>       >>
>       >> Hi all,
>       >>
>       >> One of my packages is failing on CRAN in R-devel [1], and I
>       was requested
>       >> to fix it. However, it is *only* failing on one specific
>       configuration,
>       >> 'r-devel-linux-x86_64-debian-gcc'. All other combinations —
>       clang on
>       >> Debian, both clang and GCC on Fedora, and Windows — keep
>       running just fine.
>       >> As my package is not using compiled code or anything
>       OS-specific, I am at a
>       >> loss to explain this highly specific failure. Before
>       attempting to build a
>       >> container image with this specific configuration locally (…
>       are these
>       >> configurations available as ready-made images?), I wanted to
>       check if there
>       >> was an obvious change in R-devel which might explain the
>       issue.
>       >>
>       >> There are two failures, both with the same error message:
>       “cannot change
>       >> value of locked binding for '*tmp*'”. My package’s code isn’t
>       attempting to
>       >> directly change `*tmp*`, but it is using eval() to perform
>       subset
>       >> assignment to a complex expression inside an active binding.
>       Here’s a
>       >> minimal code snippet that *should* be equivalent to one of
>       the two
>       >> failures, and which should therefore also fail (in the last
>       line):
>       >>
>       >>   x = data.frame(a = 1 : 2, b = c('a', 'b'))
>       >>
>       >>   f = function (value) {
>       >>     if (missing(value)) {
>       >>       evalq(x[1L, ], .GlobalEnv)
>       >>     } else {
>       >>       assign_expr = substitute(x[1L, ] <- value, list(value =
>       value))
>       >>       eval(assign_expr, .GlobalEnv)
>       >>     }
>       >>   }
>       >>
>       >>   makeActiveBinding('ax', f, .GlobalEnv)
>       >>
>       >>   ax[1L] = 3L
>       >>
>       >> I had a look at the changes in in R-devel, but I couldn’t
>       find anything
>       >> obviously relevant. In particular, the code of
>       R_MakeActiveBinding() hasn’t
>       >> been touched in literally decades, and similar for the code
>       that (as far as
>       >> I understand) performs subset assignment, applydefine().
>       >>
>       >> Does anybody have an idea what might be going on here, or how
>       to debug this
>       >> issue?
>       >>
>       >> Cheers,
>       >> Konrad
>       >>
>       >> [1]
>       https://cran.r-project.org/web/checks/check_results_aka.html
>       >>
>       >> --
>       >> Konrad Rudolph
>       >>
>       >> [[alternative HTML version deleted]]
>       >>
>       >> ______________________________________________
>       >> R-package-devel using r-project.org mailing list
>       >> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>       >>
>       >
>       > ______________________________________________
>       > R-package-devel using r-project.org mailing list
>       > https://stat.ethz.ch/mailman/listinfo/r-package-devel
>       >
>
>       --
>       Luke Tierney
>       Ralph E. Wareham Professor of Mathematical Sciences
>       University of Iowa                  Phone:
>        319-335-3386
>       Department of Statistics and        Fax:
>        319-335-3017
>           Actuarial Science
>       241 Schaeffer Hall                  email:
>        luke-tierney using uiowa.edu
>       Iowa City, IA 52242                 WWW:
>       http://www.stat.uiowa.edu/
> 
> 
> 
> --
> Konrad Rudolph
> 
>

-- 
Luke Tierney
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:   luke-tierney using uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu


More information about the R-package-devel mailing list