# object of type 'closure' is not(?) subsettable

## R Error message: object of type 'closure' is not subsettable

A common error in R is object of type 'closure' is not subsettable. This message means that you have a variable which represents a function, and you’re mistakenly using square brackets to try and subset it, thinking that it represents a data.frame or vector or something e.g.

# mean here refers the built-in base R function
mean[1:3]
## Error in mean[1:3]: object of type 'closure' is not subsettable

In general if you get this error it means you’re trying to subset a function (or somehow access an item within a function using $) which (most of the time) doesn’t make much sense in normal R code. ## What if objects of type ‘closure’ were subsettable? While riffing on a joke tweet, Luke Smith wondered on twitter if there was any actual case for make closures subsettable: The rest of this post is my idea for something vaguely useful you could do with subsetting a function/closure in R. ## Using subset syntax to manipulate formal arguments of functions • Aim: manipulate formal arguments of a function using [ ] or $ syntax
• E.g: Use rnorm$mean <- 100 to change the default mean for the rnorm() function. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Tell R that we want to make [ and $ generic
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[   <- function(...) {UseMethod("["  )}
[<- <- function(...) {UseMethod("[<-")}
$ <- function(...) {UseMethod("$"  )}
$<- <- function(...) {UseMethod("$<-")}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#' Enable subset with [] on a function so we can:
#' Determine the current default value for a given formal argument
#'
#' e.g.   rnorm['mean']
#'
#' @param func function
#' @param arg_name name of formal argument (character)
#'
#' @return current value of formal argument (or warning if not exists)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[.function <- [.closure <- function(func, arg_name) {
if (arg_name %in% names(formals(func))) {
formals(func)[[arg_name]]
} else {
warning("No such formal argument: ", arg_name)
}
}

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Same as above except allow:   rnorm$mean #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $.function <- $.closure <- function(func, arg_name) { func[as.character(substitute(arg_name))] } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Enable subset assignment on a function so we can: # Set the given formal argument of the function to the new default value # #' e.g. rnorm['mean'] <- 100 #' #' @param func function #' @param arg_name name of formal argument (character) #' @param value new default value for formal argument #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [<-.function <- [<-.closure <- function(func, arg_name, value) { fargs <- formals(func) fargs[[arg_name]] <- value formals(func) <- fargs func } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Same as above except allow: rnorm$mean <- 100
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$<-.function <- $<-.closure <- function(func, arg_name, value) {
func[as.character(substitute(arg_name))] <- value
func
}

## Example: changing the default values of rnorm() using function subsetting

# Find the default 'mean' for this function using '$' syntax rnorm$mean
## [1] 0

# Set new values for the default n and mean
rnorm$n <- 5 rnorm$mean <- 100

# Looking at the function, we can see that the default arguments have been changed
rnorm
## function (n = 5, mean = 100, sd = 1)
## .Call(C_rnorm, n, mean, sd)
## <environment: namespace:stats>

# And calling it, runs it with the new defaults
rnorm()
## [1]  99.37355 100.18364  99.16437 101.59528 100.32951

## Notes

• You can make objects of type ‘closure’ subsettable.
• If ‘closure’ objects are made subsettable, then you can reason about them and manipulate their arguments and code in a (possibly) intuitive manner.
• You’d probably never want to actually do this because it’s going to be super unsafe behaviour most of the time i.e. 99.9999999% of the cases, the user expects an error if they try and subset a function, not some weird thing to do with formal arguments as I’ve defined here.
• TL;DR - Fun, but don’t do it (unless you really want to)