Наследование R S4 — проблемы с проверкой достоверности и дополнительными слотами

Я пытаюсь создать класс 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 и вместо этого полагался на метод по умолчанию, а именно selectMethod("initialize", "ANY"), чтобы делать то, что я хочу...

Mikael Jagan 28.07.2024 06:26

Спасибо, вы имеете в виду, что мне не следует использовать какой-либо метод initialize? тогда как я могу проверить достоверность каждого класса? В моем примере, если я не определяю какой-либо метод initialize, достоверность проверяется правильно для «A» при создании нового экземпляра «B» без аргумента x или y, но неправильно при непосредственном создании нового экземпляра «A». (нет предупреждающего сообщения, если в этом случае `x` или y отсутствует, например, при использовании new("A")).

julien.leroux5 29.07.2024 17:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Несколько вещей:

  • Методы проверки должны возвращать 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

здорово, спасибо большое за такие пояснения! Это яснее, чем документы, которые я смог найти. Если вы знаете какое-нибудь хорошее чтение/ссылку об этих понятиях, мне было бы интересно.

julien.leroux5 29.07.2024 23:38

Другие вопросы по теме