Hi everyone,
I have a question.
Given the address of an object ("address" in the sense given by, for example, "data.table::address()"), is it possible to check if any binding in any environment pointing to that address is locked?
So a function similar to "bindingIsLocked()", except the function checks all bindings sharing the same address, instead of checking a binding by name in a specific environment.
One use-case for this is to check if it's save to modify an object by reference.
For example, when saying x <- base::letters, x is not save to modify by reference:
Although the binding of x itself is not locked, the binding of base::letters is locked, and we obviously don't want to modify base::letters.
It should be possible, I think. R has a few pass-by-reference classes (like environments), so R should be able to check something like this. I just have no idea how exactly R checks this.
Thanks in advance for any response!
Kind regards,
Tony
[R-pkg-devel] Check if any object pointing to a given address is locked
3 messages · Tony Wilkes, Ivan Krylov, Tomas Kalibera
? Thu, 24 Apr 2025 12:36:57 +0000 Tony Wilkes <tony_a_wilkes at outlook.com> ?????:
One use-case for this is to check if it's save to modify an object by reference.
I think you might need NOT_SHARED() for that, except it's far from being simple, especially once you pass arbitrary expressions (not just variable names) as arguments to your function: https://developer.r-project.org/Refcnt.html
For example, when saying x <- base::letters, x is not save to modify by reference: Although the binding of x itself is not locked, the binding of base::letters is locked, and we obviously don't want to modify base::letters.
The situation is more dangerous than that. When 'x' references the same object as base::letters (which is a locked binding), you can still modify this object from C code, given its SEXP address, and see the changes from either binding; R won't be able to stop you. (That's the danger of by-reference operations like those implemented in data.table.) On the other hand, if you assign a new value to the 'x' binding inside a given environment, base::letters and any other objects referencing it will retain their original values; there is no need to worry about other bindings being locked.
R has a few pass-by-reference classes (like environments)
These are different. You can lock a _binding_ to an environment and
still change the _value_ of that environment precisely because it's a
mutable, pass-by-reference object:
x <- new.env()
y <- x
lockBinding('x', environment())
# x$foo <- 'bar' # would signal an error, but:
assign('foo', 'bar', envir = x) # works
x$foo # [1] "bar"
identical(x, y) # [1] TRUE
R switched to reference counting by default in version 4.0. One
downside of the reference counts as currently implemented is that when
an object containing references to other objects is garbage-collected,
the reference counts of the child objects are not decremented:
x <- 1
invisible(replicate(999, list(x)))
gc(full = TRUE)
.Internal(inspect(x))
# @5618cd515488 14 REALSXP g1c1 [MARK,REF(2000)] (len=1, tl=0) 1
'x' retains a reference count of 2000 despite the 999 lists that
previously referenced it no longer exist. This is possible to change,
but at the cost of slowing down the garbage collector.
Best regards, Ivan
On 4/24/25 14:36, Tony Wilkes wrote:
Hi everyone,
I have a question.
Given the address of an object ("address" in the sense given by, for example, "data.table::address()"), is it possible to check if any binding in any environment pointing to that address is locked?
So a function similar to "bindingIsLocked()", except the function checks all bindings sharing the same address, instead of checking a binding by name in a specific environment.
One use-case for this is to check if it's save to modify an object by reference.
For example, when saying x <- base::letters, x is not save to modify by reference:
Although the binding of x itself is not locked, the binding of base::letters is locked, and we obviously don't want to modify base::letters.
The question seems to be mixing R-level abstractions with the underlying C-level abstractions. To answer whether one can modify a C-level R objects (an SEXP) in place or not, one should think in C-level R API abstractions. One can modify an R object (SEXP x) in place when NO_REFERENCES(x) is true. If this doesn't answer your question, please try to clarify it, explain what is the problem you are trying to solve. Best Tomas
It should be possible, I think. R has a few pass-by-reference classes (like environments), so R should be able to check something like this. I just have no idea how exactly R checks this. Thanks in advance for any response! Kind regards, Tony [[alternative HTML version deleted]]
______________________________________________ R-package-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-package-devel