R6 automatically sets to NULL anything I access on self
> x <- R6::R6Class("x", list(foo = function() { print(self$notexistent) }))
> xx <- x$new()
> xx$foo()
NULL
This means that if I make a typo in one access e.g. results
instead of result
it will use NULL instead of throwing an error. Is there a way to force the latter?
The self
in an R6 function is an environment. The $
operator for environments is a primitive, and as far as I can tell it can't be overwritten. By default this operator returns NULL
rather than throwing an error if the right-sided operand isn't found in the environment, and this fact has to be explicitly handled by the caller.
This isn't so different from, say, the [
operator in C++, which doesn't bounds check a vector. Unless you explicitly check your bounds, your program will crash. If you want to bounds check you need to use a different operator like .at
: these will be safer, but will also slow your software down. It boils down to priorities. You either go fast or you change syntax and check.
Therefore if you would prefer bounds-checking behaviour from self
, you need to write a different, safer accessor with different syntax.
`%$%` <- function(env, member) {
member <- deparse(substitute(member))
ls <- eval(as.call(list(quote(ls), substitute(env))),
envir = parent.frame())
if(!member %in% ls) stop(member, " is not a member of this R6 class")
eval(as.call(list(quote(`[[`), substitute(env), member)),
envir = parent.frame())
}
x <- R6::R6Class("x", list(foo = function() print(self%$%notexistent),
bar = function() print(self%$%baz),
baz = 1))
xx <- x$new()
xx$foo()
#> Error in self %$% notexistent :
#> notexistent is not a member of this R6 class
xx$bar()
#> [1] 1
You may not like the fact that you can't use the $
operator in this way, but that's the way R is. I think it's clear you don't like the language, and I can't change that, but until your plans to destroy it are realised, you can see it as a challenge...