The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
A regular R variable lives in whatever environment created it. Pass
it into a function, and the function only sees a copy; change that copy
inside the function, and the original outside is untouched. Assign
inside a for loop or an lapply() call and,
again, only the local copy changes. This is normal, sensible R scoping —
but it also means that sharing genuinely mutable state across scopes
(functions, loops, apply-family calls, nested environments)
usually forces you to reach for <<-, explicit
environments, or reference-class objects, all of which add ceremony to
what is conceptually a simple idea: “I want one variable that stays the
same object no matter where I touch it from.”
newSuperVar() creates exactly that: a super
variable — a named object that is attached to the search path
so it is visible and mutable from any scope in the current R session,
with optional protections layered on top: type/class enforcement, an
explicit lock, and a cap on how many times its value may be changed.
# Task: create a super variable to store a dataset that should not be altered
newSuperVar(mtdf, value = austres) # create a super variable named mtdf
head(mtdf) # view it like any other object
mtdf.class # view the stored class of the variable, e.g. "ts"
# once created, any new value assigned to mtdf via mtdf.set() MUST have this same class
newSuperVar(variable, value = 0L, lock = FALSE, editn = NULL)
takes the (unquoted) name you want the super variable to have, the
initial value, whether it should be locked,
and editn, an optional cap on the number of times it may
later be changed.
Two things happen the moment you call it:
mtdf becomes available by that name from
anywhere in your R session — not just the environment where you called
newSuperVar().mtdf., are attached alongside it (mtdf.set(),
mtdf.rm(), mtdf.contains(),
mtdf.round(), mtdf.signif(),
mtdf.class, plus
mtdf.push()/mtdf.pop(), and — for data frames
specifically — mtdf.head()/mtdf.tail()).Trying to declare a super variable under a name that already exists
produces an error telling you to remove the existing one first (see
.rm() below) rather than silently overwriting it.
.set() — updating the valueOrdinary reassignment (mtdf <- something_else) will
not change the super variable itself; it just creates a local variable
that happens to shadow the name in your current scope. To actually
update the stored value, use .set():
newSuperVar(edtvec, value = number(5))
edtvec # view content of the vector
# edtvec.set(letters) # ERROR: Cannot set to a value with a different class
# # than the original value (numeric here, letters is character)
edtvec.set(number(20)) # set to new numbers
edtvec # view updated output
Because .set() is a function, not a <-
assignment, it works identically no matter which scope it is called
from:
for (pu in 1:8) {
print(edtvec) # view output within the loop
edtvec.set(number(pu)) # set to new numbers within the for loop
}
lc <- lapply(1:8, function(pu) {
print(edtvec) # view output within the loop
edtvec.set(number(pu)) # set to new numbers within the lapply loop
})
# compare that to an ordinary local variable, which lapply() cannot mutate:
bim <- 198
lc <- lapply(1:8, function(j) {
print(bim)
bim <- j # only changes the local copy inside this call; outer bim is untouched
})
Every call to .set() checks the class of the new value
against the class the super variable was created with, and refuses the
update (with an informative error) if they don’t match. This is what
makes super variables safer to share across a large script than a plain
global variable: a typo that assigns the wrong kind of value is caught
immediately instead of silently corrupting downstream logic.
.round() and .signif() — numeric rounding
in placeFor numeric or data-frame-of-numeric super variables,
.round(digits) and .signif(digits) update the
stored value in place, rounding to the given number of decimal places or
significant digits respectively:
newSuperVar(mtdf3, value = beaver1, lock = TRUE)
head(mtdf3) # view original values
mtdf3.round(1) # round to 1 decimal place
head(mtdf3) # view rounded values
mtdf3.signif(2) # round to 2 significant digits
head(mtdf3) # view again
.contains() — searching the value.contains() checks whether a pattern or value is present
anywhere in the super variable, using the same matching options as
grep() (ignore.case, perl,
fixed, useBytes, invert). For
vectors it searches the vector directly; for a data frame, matrix, or
array it searches within a specific column, named via the
df.col argument:
# Task: create and search a data frame
newSuperVar(lon2, value = mtcars) # declares lon2
lon2 # view content of lon2
lon2.contains("21.0", df.col = "mpg") # search the mpg column
# for the character "21.0"
lon2.contains(21.0, df.col = "mpg") # search the mpg column
# for the numeric value 21.0
# remove lon2 as a super variable once done with it
exists("lon2") # TRUE, before removal
lon2.rm()
exists("lon2") # FALSE, after removal
# Task: create and search a vector
newSuperVar(lon3, value = number(10, seed = 12)) # declares lon3
lon3 # view content of lon3
lon3.contains(72) # TRUE/FALSE - does the vector contain 72?
lon3.contains(72, fixed = TRUE) # same search, using fixed (non-regex) matching
lon3.rm() # remove lon3 as a super variable
.push() and .pop() — building a new value
from the current one.push(add, .df = c("row", "col")) and
.pop(n = 10, .df = c("row", "col")) compute what the super
variable’s vector, list, or data frame would look like with an element
added or removed (for data frames, a row or column, controlled by
.df), and return that result — they do not
update the stored value on their own. To actually persist the change,
feed the result back into .set():
newSuperVar(queue, value = c(1, 2, 3))
queue.push(4) # returns c(1, 2, 3, 4), queue itself is still c(1, 2, 3)
queue.set(queue.push(4)) # now queue is actually updated to c(1, 2, 3, 4)
queue.set(queue.pop(1)) # drop the last element and persist the change
.head() and .tail() — previewing data
framesWhen a super variable’s initial value is a data frame, two extra
helpers are attached automatically: .head(n = 10) and
.tail(n = 10), printing the first or last n
rows. They are not created for non-data-frame super variables.
.rm() — removing a super variable.rm() detaches the super variable and all of its
companion functions, freeing up the name for reuse (including
re-declaring it with newSuperVar() again):
exists("lon3") # TRUE
lon3.rm()
exists("lon3") # FALSE
Passing lock = TRUE at creation time adds an extra layer
of protection around the stored binding, intended for values you want to
guard more strictly against being changed by anything other than the
super variable’s own methods:
newSuperVar(mtdf3, value = beaver1, lock = TRUE)
Locked or not, updates always go through .set(),
.round(), or .signif() — those methods know
how to handle the lock internally, so day-to-day usage looks identical
whether lock is TRUE or FALSE.
Use lock = TRUE for values you want to flag as
intentionally protected, such as reference datasets or configuration you
don’t want casually reassigned elsewhere in a long script.
editn caps the number of successful .set()
calls a super variable will accept:
# Task: create a super variable that can only be edited 3 times
newSuperVar(man1, value = number(5), editn = 3)
man1 # view value
man1.set(number(10)) # change value - 1st edit, succeeds
man1
man1.set(number(2)) # change value - 2nd edit, succeeds
man1
man1.set(number(1)) # change value - 3rd edit, succeeds
man1
man1.set(number(5)) # 4th attempted edit - does NOT change the value,
man1 # because the maximum of 3 edits has been used up
editn = NULL (the default) allows unlimited edits.editn = 0 prevents editing entirely — in this case,
.set() is not even attached to the super variable, so there
is no way to change its value short of removing it with
.rm() and creating it again..set() calls silently stop taking
effect.Super variables are a good fit when you want:
lapply()/sapply() calls, or nested functions,
without threading it through as an explicit argument and return value
everywhere..set()), and optionally only a limited number of times
(editn).Because a super variable’s companion functions are derived from its
name by appending suffixes like .set, .rm, and
.class, avoid using names that already end in a period
followed by one of those words for something else in the same session,
and avoid creating two super variables whose derived helper names would
collide. If you need a fresh super variable under a name you’ve already
used, call <name>.rm() first —
newSuperVar() deliberately refuses to redeclare an existing
super variable in place.
vignette("quickcode_r_introduction") for a broader tour
of the packagevignette("not_functions_data_validation_r") for the
not.* family used throughout quickcode’s own internals,
including inside newSuperVar()These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.