I was just wondering if there was a way to force a function to only accept certain data types, without having to check for it within the function; or, is this not possible b
You could write a wrapper like the following:
check.types = function(classes, func) {
n = as.name
params = formals(func)
param.names = lapply(names(params), n)
handler = function() { }
formals(handler) = params
checks = lapply(seq_along(param.names), function(I) {
as.call(list(n('assert.class'), param.names[[I]], classes[[I]]))
})
body(handler) = as.call(c(
list(n('{')),
checks,
list(as.call(list(n('<-'), n('.func'), func))),
list(as.call(c(list(n('.func')), lapply(param.names, as.name))))
))
handler
}
assert.class = function(x, cls) {
stopifnot(cls %in% class(x))
}
And use it like
f = check.types(c('numeric', 'numeric'), function(x, y) {
x + y
})
> f(1, 2)
[1] 3
> f("1", "2")
Error: cls %in% class(x) is not TRUE
Made somewhat inconvenient by R not having decorators. This is kind of hacky and it suffers from some serious problems:
You lose lazy evaluation, because you must evaluate an argument to determine its type.
You still can't check the types until call time; real static type checking lets you check the types even of a call that never actually happens.
Since R uses lazy evaluation, (2) might make type checking not very useful, because the call might not actually occur until very late, or never.
The answer to (2) would be to add static type information. You could probably do this by transforming expressions, but I don't think you want to go there.