[Rd] structure(<primitive function>, ...) is sticky: a bug, or should it be an error?
Henrik Bengtsson
henr|k@bengt@@on @end|ng |rom gm@||@com
Wed Mar 19 18:58:46 CET 2025
Hello.
I just (re-)discovered that structure(sum, init = 100) is "sticky",
i.e. it stays with base::sum(). Here's an minimal example:
$ R --vanilla --quiet
> void <- structure(sum, some_attr = TRUE)
> str(sum)
function (..., na.rm = FALSE)
- attr(*, "some_attr")= logi TRUE
>From my very basic troubleshooting, it looks like this is happening
for primitive functions. I think I understand that this comes down to
primitive functions cannot be copied and baseenv() being special, i.e.
in structure() there will be no copy made of the primitive function,
and then attributes()<- ends up modifying the original primitive
function. Even if this is a documented feature, I believe, it is a
silent feature with risky side effects. We might already have code out
there that silently produces incorrect results, because of this
behavior. For example, I was about to a custom reduce() function where
I control the initial value via an "init" attribute of the reducer
function, e.g.
x <- 1:10
sum1 <- reduce(x, `+`)
sum2 <- reduce(x, structure(`+`, init = 100)) # == 100 + sum1
If I then call:
sum3 <- reduce(x, `+`)
the 'init' attribute that was set in the sum2 statement will affect
sum3 such that sum3 == sum2, not sum3 == sum1 as one would expect.
SUGGESTIONS:
If this is a bug, then I think it needs to be fixed. If it cannot be
fixed, maybe this could be protected against, e.g.
> void <- structure(sum, some_attr = TRUE)
Error: You must not set attributes on a primitive function: sum
Maybe it's sufficient to implement a protection against this in
attr()<-, attributes()<-, and class()<-.
Comments?
/Henrik
PS. I've verified this with R 4.4.3 and R Under development
(unstable) (2025-03-19 r88003).
More information about the R-devel
mailing list