Когда инициализируется проверка на достоверность объекта? - PullRequest
1 голос
/ 07 ноября 2019

Из камер (отлично) Расширение R (2016) :

Метод валидации будет вызываться автоматически из метода по умолчанию для initialize (). Рекомендуемая форма метода initialize заканчивается вызовом callNextMethod (), чтобы гарантировать, что слоты подкласса могут быть указаны при вызове генератора для класса. Если следовать этому соглашению, инициализация закончится вызовом метода по умолчанию, и метод валидности будет вызван после того, как вся инициализация произойдет.

Я думал, что понял, но поведение, которое я получаюпохоже, не следует этому соглашению.

setClass("A", slots = c(s1 = "numeric"))

setValidity("A", function(object) {
  if (length(object@s1) > 5) {
    return("s1 longer than 5")
  }
  TRUE
})

setMethod("initialize", "A", function(.Object, s1, ...) {
  if (!missing(s1)) .Object@s1 <- s1 + 4
  callNextMethod(.Object, ...)
})

A <- new("A", rep(1.0, 6))
A
# An object of class "A"
# Slot "s1":
#   [1] 5 5 5 5 5 5
validObject(A)
# Error in validObject(A) : invalid class “A” object: s1 longer than 5

Я ожидал, что проверка достоверности будет выполнена путем добавления callNextMethod() в конец метода инициализации. Добавление явного validObject(.Object) до того, как callNextMethod() сработает, но я явно чего-то здесь не понимаю.

Очевидно, я также могу делать все те же проверки в методе достоверности, но в идеале вся проверка достоверности будетпроисходят в пределах setValidity, поэтому будущие правки сохраняются в одном месте.

Небольшое изменение функции initialize дает желаемый результат - есть ли причина использовать один подход над другим? Чемберс, похоже, предпочитает использовать .Object@<-, тогда как в другом месте я видел следующий метод (Gentlemman & Hadley).

setMethod("initialize", "A", function(.Object, s1, ...) {
  if (!missing(s1)) s1 + 4
  else s1 <- numeric()
  callNextMethod(.Object, s1 = s1, ...)
})

1 Ответ

0 голосов
/ 08 ноября 2019

Возможно, лучшее руководство получено от самого initialize - если вы проверите код для метода по умолчанию

getMethod("initialize",signature(.Object="ANY"))

, то вы увидите, что он действительно содержит явный вызов validObject в конце:

...
    validObject(.Object)
  }
  .Object
}

поэтому, если вы определите свой собственный метод initialize, самое похожее, что вы можете сделать, это вызвать его в конце вашего метода, прямо перед вызовом callNextMethod.

В вашем случае, когда вы вызываете callNextMethod, это только проверка того, что созданный вами слот является действительным numeric объектом (который он есть), а не проверка действительности более крупного объекта (который требуетслот s1 длиной не более 5 элементов)

...