Я пытаюсь создать класс B, содержащий другой класс A с дополнительными слотами (объект должен быть создан, даже если при определении класса A не передаются аргументы):
При определении класса A и создании экземпляра проверка достоверности в порядке (обнаружение пустых слотов допускается):
setClass("A",
slots = c(x = "numeric", y = "character"),
prototype = list(
x = numeric(0),
y = character(0)
),
validity=function(object){
if (length(object@x) == 0){
warning("x slot is empty")
}
if (length(object@y) == 0){
warning("y slot is empty")
}
return(TRUE)
})
setMethod("initialize", signature = "A",
definition = function(.Object, x, y)
{
if (!missing(x)) {
.Object@x <- x
} else {
.Object@x <- numeric(0)
}
if (!missing(y)) {
.Object@y <- y
} else {
.Object@y <- character(0)
}
validObject(.Object)
return(.Object)
} )
new("A", x=1:10)
# warning message "validityMethod(object) : y slot is empty"
Но при создании объекта класса B следующим образом я получаю сообщения о достоверности, даже если аргументы передаются, и они дублируются:
setClass("B",
slots = c(a = "data.frame"),
contains = "A",
validity = function(object) {
if (length(object@a) == 0) {
warning("a is empty")
}
return(TRUE)
})
setMethod("initialize", signature = "B",
definition = function(.Object, a, ...)
{
.Object@a <- a
.Object <- callNextMethod(.Object, ...)
validObject(.Object)
return(.Object)
} )
new("B", a = data.frame(10), x = 5, y = "c")
# gives warning messages:
#1: in validityMethod(object) : x slot is empty
#2: in validityMethod(object) : y slot is empty
#3: in validityMethod(object) : x slot is empty
#4: in validityMethod(object) : y slot is empty
Когда аргумент действительно отсутствует, я получаю дополнительное сообщение (снова продублированное):
new("B", a = data.frame(10), x = 5)
# warning:
#
#1: in validityMethod(object) : x slot is empty
#2: in validityMethod(object) : y slot is empty
#3: in validityMethod(as(object, superClass)) : y slot is empty
#4: in validityMethod(object) : x slot is empty
#5: in validityMethod(object) : y slot is empty
#6: in validityMethod(as(object, superClass)) : y slot is empty
Как мне избежать этих дублированных сообщений и заставить их работать (только когда аргументы действительно отсутствуют)?
Спасибо, вы имеете в виду, что мне не следует использовать какой-либо метод initialize
? тогда как я могу проверить достоверность каждого класса? В моем примере, если я не определяю какой-либо метод initialize
, достоверность проверяется правильно для «A» при создании нового экземпляра «B» без аргумента x
или y
, но неправильно при непосредственном создании нового экземпляра «A». (нет предупреждающего сообщения, если в этом случае `x` или y
отсутствует, например, при использовании new("A")
).
Несколько вещей:
TRUE
или строку символов, содержащую сообщение условия. Вызывающий метод validity (обычно validObject
) решает, что делать с сообщением об условии (т. е. сигнализировать ли об условии (обычно об ошибке) с помощью этого сообщения). В любом случае объекты формального класса являются действительными или недействительными, но никогда не являются квазидействительными или квазинедействительными, поэтому выдача validObject
предупреждения вместо ошибки действительно необычна. Если вы хотите предупредить пользователя, вызывающего new
, о слотах нулевой длины, не предполагая, что они недействительны, переместите тесты для слотов нулевой длины из методов проверки в методы initialize
.prototype=
.if (<missing>) <assign prototype> else <assign value>
в ваших методах initialize
— это клудж. Метод по умолчанию уже делает все это, поэтому отправьте его.Собираем все это вместе:
setClass("A", slots = c(x = "numeric", y = "character"))
setMethod("initialize", "A",
function(.Object, ...) {
.Object <- callNextMethod()
if (length(.Object@x) == 0L)
warning("zero-length 'x' slot")
if (length(.Object@y) == 0L)
warning("zero-length 'y' slot")
.Object
})
setClass("B", contains = "A", slots = c(a = "data.frame"))
setMethod("initialize", "B",
function(.Object, ...) {
.Object <- callNextMethod()
if (length(.Object@a) == 0L)
warning("zero-length 'a' slot")
.Object
})
> new("A")
An object of class "A"
Slot "x":
numeric(0)
Slot "y":
character(0)
Warning messages:
1: In initialize(value, ...) : zero-length 'x' slot
2: In initialize(value, ...) : zero-length 'y' slot
> new("B")
An object of class "B"
Slot "a":
data frame with 0 columns and 0 rows
Slot "x":
numeric(0)
Slot "y":
character(0)
Warning messages:
1: In .nextMethod(.Object = .Object) : zero-length 'x' slot
2: In .nextMethod(.Object = .Object) : zero-length 'y' slot
3: In initialize(value, ...) : zero-length 'a' slot
> new("B", y = "")
An object of class "B"
Slot "a":
data frame with 0 columns and 0 rows
Slot "x":
numeric(0)
Slot "y":
[1] ""
Warning messages:
1: In .nextMethod(.Object = .Object, ... = ...) : zero-length 'x' slot
2: In initialize(value, ...) : zero-length 'a' slot
здорово, спасибо большое за такие пояснения! Это яснее, чем документы, которые я смог найти. Если вы знаете какое-нибудь хорошее чтение/ссылку об этих понятиях, мне было бы интересно.
В этом конкретном случае я бы не определял никаких методов
initialize
и вместо этого полагался на метод по умолчанию, а именноselectMethod("initialize", "ANY")
, чтобы делать то, что я хочу...