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

Предварительно: я знаючто R — это функциональныйязык, поэтому, пожалуйста, не кусайтесь ; -)

У меня был отличныйопыт использования ООП-подхода во многих моих программах. Теперь мне интересно, есть ли способ провести различие между общедоступными и частными методами при использовании эталонных классов S4в 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"
    )
)

ПРИМЕЧАНИЕ

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

  1. Таким образом, определение класса остается четко организованным и его легче читать в случаях, когда определения отдельных методов становятся довольно большими.
  2. Позволяет в любой момент переключиться на функциональноевыполнение методов. Будь xэкземпляром определенного класса, вы можете вызвать foo_ref(.self=x)вместо x$foo().
  3. Это позволяет вам байт-компилировать методы с помощью компилятора::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(т.е. xa) должны иметь возможность использовать класс B's publicметоды:

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

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

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

Любая идея, как это можно указать?

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

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

23
задан Rappster 7 March 2014 в 18:28
поделиться