2

I'm looking for a method to validate S3 objects in my package Momocs.

Earlier versions of the package were written using S4, then I shifted back to S3 for the sake of flexibility, because users were more into S3, because I do not really need multiple inheritance, etc.. The main cost of this change was actually losing S4 representation / validity checking.

My problem follows: how can we prevent one from inadvertently "unvalidate" an S3 object, for instance trying to extend existing methods or manipulating object structure?

I have already written some validate function but, so far, I only validate before crucial steps, typically those turning an object from a class into another.

My question is:

  • do I want to have my cake and eat it (S3 flexibility and S4 representation checking) ? In that case, I would need to add my validate function across all the methods of my package?
  • or is there a smarter way on top of S3, something like "any time we do something on an object of a particular class, call a validate function on it"?
Community
  • 1
  • 1
Vincent Bonhomme
  • 7,235
  • 2
  • 27
  • 38

1 Answers1

2

The easiest thing would be to write a validation function for each class and pass objects through it before S3 method dispatch or within each class's method. Here's an example with a simple validation function called check_example_class for an object of class "example_class":

check_example_class <- function(x) {
  stopifnot(length(x) == 2)
  stopifnot("a" %in% names(x))
  stopifnot("b" %in% names(x))
  stopifnot(is.numeric(x$a))
  stopifnot(is.character(x$b))
  NULL
}
print.example_class <- function(x, ...) {
    check_example_class(x)
    cat("Example class object where b =", x$b, "\n")
    invisible(x)
}

# an object of the class
good <- structure(list(a = 1, b = "foo"), class = "example_class")

# an object that pretends to be of the class
bad <- structure(1, class = "example_class")

print(good) # works
## Example class object where b = foo
print(bad)  # fails
## Error: length(x) == 2 is not TRUE
Thomas
  • 43,637
  • 12
  • 109
  • 140
  • I already have such [a thing](https://github.com/vbonhomme/Momocs/blob/master/R/cl-validate.R) but I'd like to know if I could avoid adding it everywhere. Coining it in `print` is very good trick! – Vincent Bonhomme Apr 01 '16 at 19:44
  • 1
    @VincentBonhomme That's the trade-off of S3 vs. S4. You have to validate manually because S3 is literally just dispatch off the class attribute; it provides no other infrastructure for any kind of validation. – Thomas Apr 01 '16 at 20:28