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