% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/valid.R
\name{validate}
\alias{validate}
\alias{valid_eventually}
\alias{valid_implicitly}
\title{Validate an S7 object}
\usage{
validate(object, recursive = TRUE, properties = TRUE)

valid_eventually(object, fun)

valid_implicitly(object, fun)
}
\arguments{
\item{object}{An S7 object}

\item{recursive}{If \code{TRUE}, calls validator of parent classes recursively.}

\item{properties}{If \code{TRUE}, the default, checks property types before
executing the validator.}

\item{fun}{A function to call on the object before validation.}
}
\value{
Either \code{object} invisibly if valid, otherwise an error.
}
\description{
\code{validate()} ensures that an S7 object is valid by calling the \code{validator}
provided in \code{\link[=new_class]{new_class()}}. This is done automatically when constructing new
objects and when modifying properties.

\code{valid_eventually()} disables validation, modifies the object, then
revalidates. This is useful when a sequence of operations would otherwise
lead an object to be temporarily invalid, or when repeated property
modification causes a performance bottleneck because the validator is
relatively expensive.

\code{valid_implicitly()} does the same but does not validate the object at the
end. It should only be used rarely, and in performance critical code where
you are certain a sequence of operations cannot produce an invalid object.
}
\examples{
# A range class might validate that the start is less than the end
Range <- new_class("Range",
  properties = list(start = class_double, end = class_double),
  validator = function(self) {
    if (self@start >= self@end) "start must be smaller than end"
  }
)
# You can't construct an invalid object:
try(Range(1, 1))

# And you can't create an invalid object with @<-
r <- Range(1, 2)
try(r@end <- 1)

# But what if you want to move a range to the right?
rightwards <- function(r, x) {
  r@start <- r@start + x
  r@end <- r@end + x
  r
}
# This function doesn't work because it creates a temporarily invalid state
try(rightwards(r, 10))

# This is the perfect use case for valid_eventually():
rightwards <- function(r, x) {
  valid_eventually(r, function(object) {
    object@start <- object@start + x
    object@end <- object@end + x
    object
  })
}
rightwards(r, 10)

# Alternatively, you can set multiple properties at once using props<-,
# which validates once at the end
rightwards <- function(r, x) {
  props(r) <- list(start = r@start + x, end = r@end + x)
  r
}
rightwards(r, 20)
}
