Как избежать добавления .self при использовании eval в ссылочном классе в R?

Мне нужно использовать eval для вызова метода эталонного класса. Ниже пример игрушки:

MyClass <- setRefClass("MyClass",

    fields = c("my_field"),

    methods = list(

        initialize = function(){
            my_field <<- 3
        },

        hello = function(){
            "hello"
        },

        run = function(user_defined_text){
            eval(parse(text = user_defined_text))
        }
    )
)

p <- MyClass$new()
p$run("hello()") # Error: could not find function "hello" - doesn't work
p$run(".self$hello()") # "hello" - it works
p$run("hello()") # "hello" - now it works?!

p <- MyClass$new()
p$run("my_field") # 3 - no need to add .self

Думаю, я мог бы сделать eval(parse(text = paste0(".self$", user_defined_text))), но я действительно не понимаю:

  • почему .self нужен для оценки методов, а не полей?
  • почему .self больше не нужен после того, как он был использован один раз?

person nachocab    schedule 03.07.2013    source источник
comment
Это похоже на ошибку или, по крайней мере, на нежелательное поведение. Обратите внимание, что простое получение hello из p с помощью p$hello перед вызовом p$run("hello()") также позволяет последнему выполняться без ошибок. p$hello изменяет окружение p$run. Вы можете увидеть это с p <- MyClass$new(); ls(environment(p$run)); p$hello; ls(environment(p$run))   -  person Matthew Plourde    schedule 03.07.2013
comment
@MatthewPlourde Я обнаружил, что это не ошибка, она предназначена для ленивой оценки для повышения производительности. Несколько полезных ресурсов для тех, кто сталкивается с этой проблемой: R-devel, stackoverflow вопрос   -  person nachocab    schedule 03.07.2013


Ответы (1)


На вопросы «почему» всегда сложно ответить; обычно ответ "потому что". ?setRefClass у нас наконец есть

Only methods actually used will be included in the environment
corresponding to an individual object.  To declare that a method
requires a particular other method, the first method should
include a call to '$usingMethods()' with the name of the other
method as an argument. Declaring the methods this way is essential
if the other method is used indirectly (e.g., via 'sapply()' or
'do.call()'). If it is called directly, code analysis will find
it. Declaring the method is harmless in any case, however, and may
aid readability of the source code.

Я не уверен, что это полностью полезно в вашем случае, когда пользователь, по-видимому, может указать любой метод. Предлагая небольшой незаданный редакционный комментарий, я не уверен, «почему» вы хотите написать метод, который будет анализировать входной текст в методы; Сам я никогда не использовал эту парадигму.

person Martin Morgan    schedule 03.07.2013
comment
Добавление usingMethods("hello") перед eval устраняет проблему. Спасибо! - person nachocab; 03.07.2013