Подтвердить что ты не робот

Есть ли способ объявить публичные и частные методы для S4 Reference Classes?

Up-front: я am знает, что R - функциональный язык, поэтому, пожалуйста, не кусайте; -)

У меня был опыт большой с использованием подхода ООП для многих моих программ. Теперь мне интересно, есть ли способ провести различие между публичными и частными методами при использовании S4 Reference Classes в R?

Пример

Определения классов

setRefClass("B",
    field=list(
        b.1="numeric",
        b.2="logical"
    ),
    methods=list(
        thisIsPublic=function(...) {
            thisIsPublic_ref(.self=.self, ...)
        },
        thisIsPrivate=function(...) {
            thisIsPrivate_ref(.self=.self, ...)
        }
    )
)

setRefClass("A",
    field=list(
        a.1="B"
    )
)

Примечание

Я обычно не помещаю определение фактического метода в класс def, но разделяю его на метод S4 (т.е. thisIsPublic_ref) по следующим причинам:

  • Таким образом, класс def остается четко организованным и его легче читать в случаях, когда индивидуальный метод defs становится довольно большим.
  • Он позволяет в любое время переключиться на функциональное выполнение методов. Be x экземпляр определенного класса, вы можете вызвать foo_ref(.self=x) вместо x$foo().
  • Это позволяет вам байт-компилировать методы с помощью compiler::cmpfun(), который, как я думаю, невозможен, если у вас есть "простые" методы ссылочного класса.

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

Определения методов

setGeneric(
    name="thisIsPublic_ref",
    signature=c(".self"),
    def=function(
        .self,
        ...
    ) {
    standardGeneric("thisIsPublic_ref")    
    }
)
setGeneric(
    name="thisIsPrivate_ref",
    signature=c(".self"),
    def=function(
        .self,
        ...
    ) {
    standardGeneric("thisIsPrivate_ref")    
    }
)

require(compiler)

setMethod(
    f="thisIsPublic_ref",
    signature=signature(.self="B"),
    definition=cmpfun(function(  
        .self,
        ...
    ){
    .self$b.1 * 1000
    })
)
setMethod(
    f="thisIsPrivate_ref",
    signature=signature(.self="B"),
    definition=cmpfun(function(  
        .self,
        ...
    ){
    .self$b.2
    })
)

Экземпляры

x.b <- new("B", b.1=10, b.2=TRUE)
x.a <- new("A", a.1=x.b, a.2="hello world")

Открытый и закрытый

Для экземпляров класса A (т.е. x.a) следует использовать методы класса B public:

> x.a$a.1$thisIsPublic()
[1] 10000

Экземпляры класса A (т.е. x.a) должны иметь не, чтобы использовать методы класса B private. Поэтому я хотел бы, чтобы этот не работал, то есть приводил к ошибке:

> x.a$a.1$thisIsPrivate()
[1] TRUE

Любая идея, как это можно было бы определить?

Единственное, что я придумал до сих пор:

Добавление аргумента sender для каждого метода, явно указать его для каждого вызова метода и проверить, есть ли class(.self) == class(sender). Но это кажется немного "явным".

4b9b3361

Ответ 1

Как функции являются первоклассными объектами в R, вы можете вставлять их внутри другого, как показано ниже:

hello <- function() {
    print_ <- function() { 
         return ('hello world')
    }
    print_()
}

Да, это нахальный, возможно, не самый чистый способ, но он работает... Вызовите использование "hello()".

Ответ 2

Короткий ответ - сделать пакет. R объектные системы, и это означает, что код разбиения (пространства имен) более раздельный, чем их эквиваленты в Java-подобных языках.

Когда вы создаете пакет, вы указываете, что экспортируется в файл NAMESPACE с помощью директив export и exportMethods. Вы можете выбрать не экспортировать методы и другие объекты R, которые вы хотите быть приватными (использовать терминологию Java). См. Раздел Пространства имен с разделом классов S4 и методов руководства по расширению Writing R

Создание пакета сложно в первый раз, когда вы это делаете, но там много помощи. См. Документы для package.skeleton и руководство по написанию расширений "Написание R", приведенное выше.

Убедитесь, что классы справки действительно то, что вы хотите. Обычные классы S4 обычно больше R-ish, для чего бы то ни было. Большой источник информации о R многих конструкциях OO (и об упаковке тоже) находится на Hadley Wickham devtools wiki.