R та об'єктно-орієнтоване програмування


80

Об'єктно-орієнтоване програмування тим чи іншим чином дуже можливо в R. Однак, на відміну, наприклад, від Python, існує безліч способів досягнення об'єктної орієнтації:

Моє запитання:

Які основні відмінності відрізняють ці способи програмування ОО в R?

В ідеалі відповіді тут слугуватимуть довідковими для програмістів R, які намагаються вирішити, які методи програмування ОО найкраще відповідають їхнім потребам.

Як такий, я прошу детально, подати його об’єктивно, на основі досвіду та підкріпивши фактами та посиланнями. Бонусні бали за пояснення того, як ці методи відповідають стандартним практикам ОО.


1
Інформація про довідкові класи: stackoverflow.com/questions/5137199/…
Арі Б. Фрідман

Дякуємо, чи можете ви розмістити посилання як відповідь? Було б непогано, якщо б ви могли включити невеликий підсумок того, що таке довідкові класи, і чому вони є кращими стосовно класів S3 / S4.
Пол Хімстра

Маленька пташка прошептала мені на вухо, що про це з’явиться книга Джона Чемберса. Але нікому не кажіть, що я сказав, що ... ;-)
Дірк Еддельбюттель

1
Чи міг би той самий маленький пташиний наклеїти відповідь нижче з додатковою інформацією про уроки референції;)
Пол Хімстра

Відповіді:


34

S3 класи

  • Насправді не об'єкти, більше домовленості про іменування
  • Заснований навколо. синтаксис: Наприклад, для друку, printдзвінків print.lm print.anovaтощо. А якщо не знайдено,print.default

Класи S4

Довідкові класи

прото

  • ggplot2 спочатку був написаний у прото, але з часом буде переписаний за допомогою S3.
  • Акуратна концепція (прототипи, а не класи), але на практиці здається складною
  • Наступна версія ggplot2, схоже, віддаляється від неї
  • Опис концепції та реалізації

Класи R6

  • Довідкове посилання
  • Не залежить від класів S4
  • " Створення класу R6 подібне до довідкового класу, за винятком того, що немає необхідності відокремлювати поля та методи, і ви не можете вказати типи полів."

1
Не соромтеся редагувати, якщо у вас є інші розбіжності. Я не буду плакати, якщо стане CW :-)
Арі Б. Фрідман

3
не забувайтеlibrary("fortunes"); fortune("strait")
Бен Болкер

1
Обговорення класів S4 тут: stackoverflow.com/questions/3602154/… . Загальне відчуття полягає в тому, що їм більше проблем, ніж вони надають перевагу.
Пол Хімстра

Цікаво, що нові класи R6 неявно визнають, що еталонні класи були R5, уникаючи використання цього числа. Нехай суперечка розпочнеться (заново).
Ari B. Friedman

1
Ім'я R5 спочатку використовували як жарт не лише розробники довідкових класів. Назва R6 є визнанням "R5", але це не означає, що назва R5 мала будь-яке офіційне підтвердження.
wch

19

Редагувати 3/8/12: Відповідь нижче відповідає на частину спочатку розміщеного питання, яке з тих пір було видалено. Я скопіював його нижче, щоб надати контекст для моєї відповіді:

Як різні методи OO співпадають із більш стандартними методами OO, що використовуються, наприклад, у Java або Python?


Мій внесок пов’язаний з вашим другим питанням про те, як методи ОО R відповідають більш стандартним методам ОО. Коли я думав про це в минулому, я знову і знову повертався до двох уривків, одного Фрідріха Лейша, а іншого Джона Чемберса. Обидва вони добре формулюють, чому OO-подібне програмування в R має інший смак, ніж у багатьох інших мовах.

По-перше, Фрідріх Лейш, з "Створення пакетів R: Підручник" ( попередження: PDF ):

S рідкісний, оскільки він одночасно інтерактивний і має систему об’єктної орієнтації. Очевидно, що проектування класів є програмуванням, проте, щоб зробити S корисним як середовище інтерактивного аналізу даних, має сенс, що це функціональна мова. У "реальних" об'єктно-орієнтованих програмуваннях (ООП) мови, такі як C ++ або Java, визначення класів і методів тісно пов'язані між собою, методи є частиною класів (а отже, і об'єктів). Ми хочемо додаткові та інтерактивні доповнення, як визначені користувачем методи для попередньо визначених класів. Ці доповнення можна зробити в будь-який момент часу, навіть на льоту в командному рядку, поки ми аналізуємо набір даних. S намагається піти на компроміс між орієнтацією на об'єкт та інтерактивним використанням, і хоча компроміси ніколи не є оптимальними щодо всіх цілей, яких вони намагаються досягти, вони часто на диво добре працюють на практиці.

Інший уривок виходить із чудової книги Джона Чемберса "Програмне забезпечення для аналізу даних" . ( Посилання на цитований уривок ):

Модель програмування ООП відрізняється від мови S усім, крім першого, хоча S і деякі інші функціональні мови підтримують класи та методи. Визначення методів у системі ООП є локальними для класу; немає вимоги, щоб одне і те ж ім'я методу означало те саме для не пов'язаного класу. На відміну від цього, визначення методів у R не містяться у визначенні класу; концептуально вони пов'язані із родовою функцією. Визначення класів вводяться при визначенні методу вибору, безпосередньо або шляхом успадкування. Програмісти, які звикли до моделі ООП, іноді розчаровані або розгублені тим, що їх програмування не переходить безпосередньо на R, але не може. Функціональне використання методів є більш складним, але також більш налаштованим на наявність значущих функцій і не може бути зведене до версії ООП.


14

S3 та S4, схоже, є офіційними (тобто вбудованими) підходами до програмування ОО. Я почав використовувати комбінацію S3 з функціями, вбудованими в функцію / метод конструктора. Моєю метою було мати синтаксис типу $ method (), щоб у мене були напівзакриті поля. Я кажу напівприватним, тому що насправді їх неможливо приховати (наскільки мені відомо). Ось простий приклад, який насправді нічого не робить:

#' Constructor
EmailClass <- function(name, email) {
    nc = list(
        name = name,
        email = email,
        get = function(x) nc[[x]],
        set = function(x, value) nc[[x]] <<- value,
        props = list(),
        history = list(),
        getHistory = function() return(nc$history),
        getNumMessagesSent = function() return(length(nc$history))
    )
    #Add a few more methods
    nc$sendMail = function(to) {
        cat(paste("Sending mail to", to, 'from', nc$email))
        h <- nc$history
        h[[(length(h)+1)]] <- list(to=to, timestamp=Sys.time())
        assign('history', h, envir=nc)
    }
    nc$addProp = function(name, value) {
        p <- nc$props
        p[[name]] <- value
        assign('props', p, envir=nc)
    }
    nc <- list2env(nc)
    class(nc) <- "EmailClass"
    return(nc)
}

#' Define S3 generic method for the print function.
print.EmailClass <- function(x) {
    if(class(x) != "EmailClass") stop();
    cat(paste(x$get("name"), "'s email address is ", x$get("email"), sep=''))
}

І кілька тестових кодів:

    test <- EmailClass(name="Jason", "jason@bryer.org")
    test$addProp('hello', 'world')
    test$props
    test
    class(test)
    str(test)
    test$get("name")
    test$get("email")
    test$set("name", "Heather")
    test$get("name")
    test
    test$sendMail("jbryer@excelsior.edu")
    test$getHistory()
    test$sendMail("test@domain.edu")
    test$getNumMessagesSent()

    test2 <- EmailClass("Nobody", "dontemailme@nowhere.com")
    test2
    test2$props
    test2$getHistory()
    test2$sendMail('nobody@exclesior.edu')

Ось посилання на допис у блозі, який я писав про цей підхід: http://bryer.org/2012/object-oriented-programming-in-r. Я вітаю коментарі, критику та пропозиції щодо цього підходу, оскільки я не переконаний я, якщо це найкращий підхід. Однак проблема, яку я намагався вирішити, чудово спрацювала. Зокрема, для пакету makeR ( http://jbryer.github.com/makeR ) я не хотів, щоб користувачі безпосередньо змінювали поля даних, тому що мені потрібно було забезпечити синхронізацію XML-файлу, що представляє стан мого об’єкта. Це працювало чудово, доки користувачі дотримуються правил, які я виклав у документації.


10
Ви начебто заново вигадуєте довідкові класи "від руки" з наведеним вище кодом ... Це просто робить справу трохи крихкішою.
Саймон Урбанек

Дякую Саймоне. Я не знав про ReferenceClasses, поки не опублікував це.
jbryer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.