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, <[email protected]> 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
      <[email protected]> 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]]
      >>
      >> ______________________________________________
      >> [email protected] mailing list
      >> https://stat.ethz.ch/mailman/listinfo/r-package-devel
      >>
      >
      > ______________________________________________
      > [email protected] 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:
       [email protected]
      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:   [email protected]
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu
______________________________________________
[email protected] mailing list
https://stat.ethz.ch/mailman/listinfo/r-package-devel

Reply via email to