One possibility is to check the value of the return type after method dispatch
setGeneric("getScalar", function(x, ...) {
value <- standardGeneric("getScalar")
if (!is.atomic(value) || length(value) != 1L)
stop("not a scalar atomic vector")
value
})
setMethod(getScalar, "ANY", function(x, ...) x)
Another possibility is to define a 'Scalar' class, with a validity check on the base class that enforces the constraint
.Scalar <- setClass("Scalar", contains="ANY", validity=function(object) {
if (length(object) != 1L)
"non-scalar object"
else TRUE
}, prototype=NA)
or controlling scalar types more strongly with a small hierarchy based on a virtual class
setClass("Scalar", validity=function(object) {
if (length(object) != 1L)
"non-scalar object"
else TRUE
})
.ScalarInteger <- setClass("ScalarInteger",
contains=c("Scalar", "integer"),
prototype=prototype(NA_integer_))
This is the approach taken in Bioconductor's Biobase package, with a mkScalar
constructor.