For the access a$b
, yes, this is possible – if messy. The reason is that $
is just an operator that we can redefine.
The default definition can be retrieved as follows:
> `$`
.Primitive("$")
It’s easy enough possible to change this so that we first test whether the b
in a$b
actually exists. Here’s a rough outline (but only a rough outline, see below):
`$` <- function (a, b) {
if (exists(as.character(substitute(b)), where = a))
.Primitive("$")(a, b)
else
methodMissing(as.character(substitute(a)), as.character(substitute(b)))
}
… now we just need to supply methodMissing
:
methodMissing <- function (a, b)
cat(sprintf('Requested missing %s on %s\n', b, a))
… and we can use it:
> foo <- list(bar = 'Hello')
> foo$bar
[1] "hello"
> foo$baz
Requested missing baz on foo
However, note that this breaks in interesting ways for other types – for instance, it no longer works with data frames:
> cars$speed
NULL
I don’t know whether it’s trivial to fix this – it’s not enough to test for is.list(a)
, for instance – so proceed with caution.
The solutions for S3 and S4 are left as an exercise for the reader (actually, I have no clue – I don’t use S4 and rarely use S3).