List or Lock All Currently Existing Bindings Pointing To Same Address
Source:R/currentBindings.R
currentBindings.Rd
currentBindings(x, action = "list")
lists all currently existing objects
sharing the same address as x
, in a given environment. currentBindings(x, action = "checklock")
searches all currently existing objects
sharing the same address as x
, in a given environment,
and reports which of these are locked and which are not locked. currentBindings(x, action = "lockbindings")
searches all currently existing objects
sharing the same address as x
, in a given environment,
and locks them using lockBinding.
See also squarebrackets_PassByReference for information regarding
the relation between locked bindings and pass-by-reference modifications.
Arguments
- x
the existing variable whose address to use when searching for bindings.
- action
a single string, giving the action to perform.
Must be one of the following:"list"
(default)."checklock"
."lockbindings"
.
- env
the environment where to look for objects.
IfNULL
(default), the caller environment is used.
Value
For currentBindings(x, action = "list")
:
Returns a character vector.
For currentBindings(x, action = "checklock")
:
Returns a named logical vector.
The names give the names of the bindings,
and each associated value indicates whether the binding is
locked (TRUE
) or not locked (FALSE
).
For currentBindings(x, action = "lockbindings")
:
Returns VOID. It just locks the currently existing bindings.
To unlock the bindings, remove the objects (see rm).
Details
The lockBinding function locks a binding of an object,
preventing modification.
'R' also uses locked bindings to prevent modification of objects from package namespaces.
The pass-by-reference semantics of 'squarebrackets' in principle respect this,
and disallows modification of objects by reference.
However, lockBinding does not lock the address/pointer of an object,
only one particular binding of an object.
This problematic; consider the following example:
x <- mutable_atomic(1:16)
y <- x
lockBinding("y", environment())
sb_set(x, i = 1:6, rp = 8)
In the above code, x
and y
share the same address,
thus pointing to the same memory,
yet only y
is actually locked.
Since x
is not locked, modifying x
is allowed.
But since sb_set()
/sb2_set()
performs modification by reference,
y
will still be modified, despite being locked.
The currentBindings()
function
allows to user to:
find all currently existing bindings in the caller environment
sharing the same address as x
,
and locking all these bindings.
Warning
The currentBindings()
function
only locks currently existing bindings
in the specified environment;
bindings that are created after calling currentBindings()
will not automatically be locked.
Thus, every time the user creates a new binding of the same object,
and the user wishes it to be locked,
currentBindings()
must be called again.
Examples
x <- as.mutable_atomic(1:10)
y <- x
lockBinding("y", environment())
currentBindings(x)
#> searching environment: <0000020f362396f0>
#> [1] "x" "y"
currentBindings(x, "checklock") # only y is locked
#> searching environment: <0000020f362396f0>
#> x y
#> FALSE TRUE
# since only y is locked, we can still modify y through x by reference:
sb_set(x, i = 1, rp = -1)
#> coercing replacement to integer
print(y) # modified!
#> [1] -1 2 3 4 5 6 7 8 9 10
#> mutable_atomic
#> typeof: integer
rm(list= c("y")) # clean up
# one can fix this by locking ALL bindings:
y <- x
currentBindings(x, "lockbindings") # lock all
#> searching environment: <0000020f362396f0>
currentBindings(x, "checklock") # all bindings are locked, including y
#> searching environment: <0000020f362396f0>
#> x y
#> TRUE TRUE
# the 'squarebrackets' package respects the lock of a binding,
# provided all bindings of an address are locked;
# so this will give an error, as it should:
if(requireNamespace("tinytest")) {
tinytest::expect_error(
sb_set(x, i = 1, rp = -1),
pattern = "object is locked"
)
}
#> ----- PASSED : <-->
#> call| eval(expr, envir)
# creating a new variable will NOT automatically be locked:
z <- y # new variable; will not be locked!
currentBindings(x, "checklock") # z is not locked
#> searching environment: <0000020f362396f0>
#> x y z
#> TRUE TRUE FALSE
currentBindings(x, "lockbindings") # we must re-run this
#> searching environment: <0000020f362396f0>
currentBindings(x, "checklock") # now z is also locked
#> searching environment: <0000020f362396f0>
#> x y z
#> TRUE TRUE TRUE
if(requireNamespace("tinytest")) {
tinytest::expect_error( # now z is also protected
sb_set(z, i = 1, rp = -1),
pattern = "object is locked"
)
}
#> ----- PASSED : <-->
#> call| eval(expr, envir)
rm(list= c("x", "y", "z")) # clean up