Плохо ли обращаться к слотам объектов S4 напрямую, используя @? - PullRequest
19 голосов
/ 28 марта 2012

Это почти философский вопрос: плохо ли получать доступ и / или устанавливать слоты объектов S4 напрямую, используя @?

Мне всегда говорили, что это плохая практика, и что пользователи должныиспользовать методы «доступа» S4, и разработчики должны предоставить их своим пользователям.Но я хотел бы знать, знает ли кто-нибудь реальную сделку за этим?

Вот пример использования пакета sp (но может быть обобщен для любого класса S4):

> library(sp)
> foo <- data.frame(x = runif(5), y = runif(5), bar = runif(5))
> coordinates(foo) <- ~x+y
> class(foo)
[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"

> str(foo)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
  ..@ data       :'data.frame': 5 obs. of  1 variable:
  .. ..$ bar: num [1:5] 0.621 0.273 0.446 0.174 0.278
  ..@ coords.nrs : int [1:2] 1 2
  ..@ coords     : num [1:5, 1:2] 0.885 0.763 0.591 0.709 0.925 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : chr [1:2] "x" "y"
  ..@ bbox       : num [1:2, 1:2] 0.591 0.155 0.925 0.803
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:2] "x" "y"
  .. .. ..$ : chr [1:2] "min" "max"
  ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slots
  .. .. ..@ projargs: chr NA

> foo@data
        bar
1 0.6213783
2 0.2725903
3 0.4458229
4 0.1743419
5 0.2779656
> foo@data <- data.frame(bar = letters[1:5], baz = runif(5))
> foo@data
  bar        baz
1   a 0.22877446
2   b 0.93206667
3   c 0.28169866
4   d 0.08616213
5   e 0.36713750

Ответы [ 4 ]

16 голосов
/ 28 марта 2012

В этот вопрос стек-поток спрашивает, почему они не могут найти слот end в Bioconductor IRanges объекте;В конце концов, есть start(), width() и end() аксессоры и start и width слоты.Ответ заключается в том, что способ взаимодействия пользователя с классом отличается от способа его реализации.В этом случае реализация обусловлена ​​простым наблюдением, что неэффективно хранить три значения (начало, конец, ширина), когда достаточно только двух (что два - до разработчика!).Подобные, но более глубокие примеры расхождения между интерфейсом и реализацией присутствуют в других объектах S4 и в общих экземплярах S3, таких как тот, который возвращается lm, где данные, хранящиеся в классе, подходят для последующих вычислений, а не предназначены для представления величин, которыеконкретный пользователь может быть больше всего заинтересован. Ничего хорошего не получится, если вы дойдете до этого экземпляра lm и измените значение, например, элемент coefficients.Такое отделение интерфейса от реализации дает разработчику большую свободу в предоставлении разумного и постоянного пользовательского опыта, возможно, совместно с другими подобными классами, но для реализации (и изменения реализации) классов таким образом, чтобы это имело смысл программирования.

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

12 голосов
/ 28 марта 2012

Короче говоря, разработчик должен предоставить методы для каждого варианта использования, но на практике это чертовски сложно и сложно охватить все возможные варианты использования.Технически и, насколько мне известно, если вам нужно больше, чем предоставляет разработчик , и вы должны использовать «@», чтобы получить неэкспонированные функции, то вы являетесь разработчиком (различиерадостно размыто здесь в программном обеспечении GNU).

Пакет sp является хорошим примером для того, чтобы задать этот вопрос, поскольку сложности иерархических структур данных, требуемые "полигонами" и "линиями", поднимают некоторые довольно простые проблемы.Вот один из них:

Метод coordinates() для многоугольников и линий возвращает только центроид для каждого объекта, хотя для точек он возвращает каждую «координату» объекта, но это потому, что «Точки» являются «единым целым».-к одному".Один объект, одна координата, правда также для SpatialPoints и SpatialPointsDataFrame.Это не относится к линиям и многоугольникам, или линиям и многоугольникам, или SpatialLines и SpatialPolygons, или SpatialLinesDataFrame и SpatialPolygonsDataFrame.Они составлены по существу из> двух дорожек координатной линии или> трехкоординатных поли "колец".Как получить координаты каждой вершины в каждом многоугольнике из каждого разветвленного SpatialPolygon?Вы не можете, если вы не углубляетесь в структуру разработчика с помощью "@".

Разве упущение разработчиков не предоставило это?Нет, преимущества намного перевешивают проблемы, которые любой конкретный пользователь может увидеть в ретроспективе.В общем, тот факт, что вы можете вникать, является огромным бонусом, но вы автоматически берете на себя ответственность разработчика и, вероятно, усложняете ситуацию, если решите поделиться своими усилиями, не заключая их в методы.

10 голосов
/ 28 марта 2012

Как разработчик класса S4, мое мнение таково:

Если вы читаете слотов с помощью @, вы делаете это на свой страх и риск (как и почти все, что вы делаете в R - см. Некоторые известные примеры ниже). При этом слоты класса S4 фактически являются частью документированного интерфейса .

Основные преимущества доступа через @ Я вижу скорость:

> microbenchmark (accessor = wl (chondro), direct = chondro@wavelength)
Unit: nanoseconds
      expr    min       lq   median       uq    max
1 accessor 333431 341289.5 346784.5 366737.5 654219
2   direct    165    212.5    395.0    520.0   1440

(функция доступа выполняет проверку валидности в дополнение к возвращению слота @wavelength, который вызывает разницу. Я ожидаю, что каждая приличная функция открытого доступа будет обеспечивать достоверность)

Я даже рекомендую использовать доступ на чтение к слотам моего класса в критических по времени ситуациях (например, если к множеству подмножеств одного и того же объекта обращаются, может быть, стоит каждый раз пропускать проверку достоверности неизмененного объекта) и в коде моего пакета я преимущественно читаю слоты напрямую, обеспечивая достоверность в начале и в конце функций, где объект мог стать недействительным. Кто-то может утверждать, что проектное решение (R) о том, что @<- не проверяет достоверность, на практике приводит к огромным накладным расходам, поскольку методы, работающие с объектами S4, не могут полагаться на действительность объекта, и, следовательно, даже методы с чисто правами чтения должны проверка достоверности.

Если вы думаете о записи доступа к слоту, вы должны действительно знать, что вы делаете. @<- не не выполняет проверку достоверности, это должен делать официальный метод записи. Кроме того, средство записи может делать гораздо больше, чем просто обновлять один слот, чтобы поддерживать согласованное состояние объекта.

Итак, если вы пишете в слот, ожидайте, что окажетесь в аду и не жалуйтесь. ; -)

Подумайте немного дальше по философской линии: моя посылка общедоступна под лицензией GPL. Я не только позволяю вам адаптировать код к вашим потребностям, но я хочу призвать вас разрабатывать / адаптировать код для ваших нужд. На самом деле это очень просто в R - все уже есть в обычном интерактивном R-сеансе, включая доступ к слотам. Что вполне соответствует проектным решениям, которые делают R очень мощным, но допускают такие вещи, как

> T <- FALSE
> `+` <- `-`
> pi <- 3
> pi + 2
[1] 1
7 голосов
/ 28 марта 2012

В целом, это хорошая практика программирования для отделения содержимого объекта от интерфейса, см. эту статью в Википедии . Идея состоит в том, чтобы отделить интерфейс от реализации, чтобы реализация могла значительно измениться, не затрагивая код, взаимодействующий с этим кодом, например, твой сценарий Следовательно, использование @ создает менее надежный код, который с меньшей вероятностью будет работать через несколько лет. Например, в пакете sp, упомянутом @mdsummer, реализация того, как хранятся полигоны, может измениться из-за скорости или прогрессирующих знаний. Используя @, ваш код ломается, используя интерфейс, который работает до сих пор. За исключением конечно, если интерфейс также изменяется. Но изменения в реализации гораздо более вероятны, чем изменения интерфейса.

...