R und objektorientierte Programmierung

80

Objektorientierte Programmierung auf die eine oder andere Weise ist in R sehr gut möglich. Im Gegensatz zu beispielsweise Python gibt es jedoch viele Möglichkeiten, eine Objektorientierung zu erreichen:

Meine Frage ist:

Welche Hauptunterschiede unterscheiden diese Arten der OO-Programmierung in R?

Im Idealfall dienen die Antworten hier als Referenz für R-Programmierer, die versuchen zu entscheiden, welche OO-Programmiermethoden ihren Anforderungen am besten entsprechen.

Als solches bitte ich um Details, die objektiv, erfahrungsbasiert und mit Fakten und Referenzen versehen sind. Bonuspunkte für die Klärung, wie diese Methoden den Standard-OO-Praktiken zugeordnet werden.

Paul Hiemstra
quelle
1
Infos zu Referenzklassen: stackoverflow.com/questions/5137199/…
Ari B. Friedman
Danke, könnten Sie den Link als Antwort erneut veröffentlichen? Es wäre schön, wenn Sie eine kleine Zusammenfassung der Referenzklassen hinzufügen könnten und warum sie in Bezug auf S3 / S4-Klassen vorzuziehen sind.
Paul Hiemstra
Ein kleiner Vogel flüsterte mir ins Ohr, dass John Chambers ein Buch darüber herausbringen wird. Aber sag niemandem, dass ich das gesagt habe ... ;-)
Dirk Eddelbuettel
1
Könnte derselbe kleine Vogel eine Antwort unten mit einigen weiteren Informationen zu Refenence-Klassen einfügen;)
Paul Hiemstra

Antworten:

34

S3-Klassen

  • Nicht wirklich Objekte, eher eine Namenskonvention
  • Basierend auf dem. Syntax: ZB für Druck, printAufrufe print.lm print.anovausw. Und wenn nicht gefunden,print.default

S4 Klassen

Referenzklassen

Proto

  • ggplot2 wurde ursprünglich in Proto geschrieben, wird aber eventuell mit S3 neu geschrieben.
  • Ordentliches Konzept (Prototypen, keine Klassen), scheint aber in der Praxis schwierig
  • Die nächste Version von ggplot2 scheint sich davon zu entfernen
  • Beschreibung des Konzepts und der Umsetzung

R6 Klassen

  • Referenz
  • Hängt nicht von S4-Klassen ab
  • " Das Erstellen einer R6-Klasse ähnelt der Referenzklasse, außer dass die Felder und Methoden nicht getrennt werden müssen und Sie die Feldtypen nicht angeben können."
Ari B. Friedman
quelle
1
Fühlen Sie sich frei zu bearbeiten, wenn Sie andere Unterschiede hinzufügen müssen. Ich werde nicht weinen, wenn es CW wird :-)
Ari B. Friedman
3
nicht vergessenlibrary("fortunes"); fortune("strait")
Ben Bolker
1
Eine Diskussion über S4-Klassen hier: stackoverflow.com/questions/3602154/… . Das allgemeine Gefühl scheint zu sein, dass sie mehr Ärger machen als einen Vorteil bringen.
Paul Hiemstra
Interessanterweise erkennen die neuen R6-Klassen implizit an, dass Referenzklassen R5 waren, indem sie die Verwendung dieser Nummer vermeiden. Lassen Sie die Kontroverse beginnen (neu).
Ari B. Friedman
1
Der Name R5 wurde ursprünglich von anderen Personen als den Entwicklern von Referenzklassen als Scherz verwendet. Der Name R6 ist eine Bestätigung von "R5", aber es soll nicht bedeuten, dass der Name R5 eine offizielle Bestätigung hatte.
wch
19

Bearbeiten am 08.03.12: Die folgende Antwort antwortet auf einen Teil der ursprünglich gestellten Frage, der inzwischen entfernt wurde. Ich habe es unten kopiert, um den Kontext für meine Antwort bereitzustellen:

Wie ordnen sich die verschiedenen OO-Methoden den Standard-OO-Methoden zu, die beispielsweise in Java oder Python verwendet werden?


Mein Beitrag bezieht sich auf Ihre zweite Frage, wie die OO-Methoden von R auf Standard-OO-Methoden abgebildet werden. Wie ich in der Vergangenheit darüber nachgedacht habe, bin ich immer wieder zu zwei Passagen zurückgekehrt, eine von Friedrich Leisch und die andere von John Chambers. Beide artikulieren gut, warum OO-ähnliche Programmierung in R einen anderen Geschmack hat als in vielen anderen Sprachen.

Zunächst Friedrich Leisch aus "Erstellen von R-Paketen: Ein Tutorial" ( Warnung: PDF ):

S ist selten, weil es sowohl interaktiv als auch objektorientiert ist. Das klare Entwerfen von Klassen ist eine Programmierung. Um S jedoch als interaktive Datenanalyseumgebung nützlich zu machen, ist es sinnvoll, dass es sich um eine funktionale Sprache handelt. In "echten" objektorientierten Programmiersprachen (OOP) wie C ++ oder Java sind Klassen- und Methodendefinitionen eng miteinander verbunden, Methoden sind Teil von Klassen (und damit Objekten). Wir möchten inkrementelle und interaktive Ergänzungen wie benutzerdefinierte Methoden für vordefinierte Klassen. Diese Ergänzungen können zu jedem Zeitpunkt vorgenommen werden, auch im laufenden Betrieb an der Eingabeaufforderung, während wir einen Datensatz analysieren. S versucht, einen Kompromiss zwischen Objektorientierung und interaktiver Nutzung einzugehen, und obwohl Kompromisse in Bezug auf alle Ziele, die sie erreichen möchten, niemals optimal sind, funktionieren sie in der Praxis oft überraschend gut.

Die andere Passage stammt aus John Chambers 'großartigem Buch "Software for Data Analysis" . ( Link zur zitierten Passage ):

Das OOP-Programmiermodell unterscheidet sich von der S-Sprache in allen bis auf den ersten Punkt, obwohl S und einige andere funktionale Sprachen Klassen und Methoden unterstützen. Methodendefinitionen in einem OOP-System sind für die Klasse lokal. Es ist nicht erforderlich, dass der gleiche Name für eine Methode für eine nicht verwandte Klasse dasselbe bedeutet. Im Gegensatz dazu befinden sich Methodendefinitionen in R nicht in einer Klassendefinition. konzeptionell sind sie mit der generischen Funktion verbunden. Klassendefinitionen werden direkt oder durch Vererbung bei der Bestimmung der Methodenauswahl berücksichtigt. Programmierer, die an das OOP-Modell gewöhnt sind, sind manchmal frustriert oder verwirrt, dass ihre Programmierung nicht direkt auf R übertragen wird, dies jedoch nicht kann. Der funktionale Einsatz von Methoden ist komplizierter, aber auch besser auf sinnvolle Funktionen abgestimmt und kann nicht auf die OOP-Version reduziert werden.

Josh O'Brien
quelle
14

S3 und S4 scheinen die offiziellen (dh eingebauten) Ansätze für die OO-Programmierung zu sein. Ich habe begonnen, eine Kombination von S3 mit Funktionen zu verwenden, die in die Konstruktorfunktion / -methode eingebettet sind. Mein Ziel war es, eine Syntax vom Typ object $ method () zu haben, damit ich halbprivate Felder habe. Ich sage halbprivat, weil es keine Möglichkeit gibt, sie wirklich zu verstecken (soweit ich weiß). Hier ist ein einfaches Beispiel, das eigentlich nichts tut:

#' 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=''))
}

Und ein Testcode:

    test <- EmailClass(name="Jason", "[email protected]")
    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("[email protected]")
    test$getHistory()
    test$sendMail("[email protected]")
    test$getNumMessagesSent()

    test2 <- EmailClass("Nobody", "[email protected]")
    test2
    test2$props
    test2$getHistory()
    test2$sendMail('[email protected]')

Hier ist ein Link zu einem Blog-Beitrag, den ich über diesen Ansatz geschrieben habe: http://bryer.org/2012/object-oriented-programming-in-r Ich würde Kommentare, Kritik und Vorschläge zu diesem Ansatz begrüßen, da ich nicht überzeugt bin ich selbst, wenn dies der beste Ansatz ist. Für das Problem, das ich zu lösen versuchte, hat es jedoch großartig funktioniert. Insbesondere für das makeR-Paket ( http://jbryer.github.com/makeR ) wollte ich nicht, dass Benutzer Datenfelder direkt ändern, da ich sicherstellen musste, dass eine XML-Datei, die den Status meines Objekts darstellt, synchron bleibt. Dies funktionierte einwandfrei, solange die Benutzer die in der Dokumentation beschriebenen Regeln einhalten.

jbryer
quelle
10
Sie erfinden die Referenzklassen mit dem obigen Code "von Hand" neu ... Das macht die Sache nur ein bisschen zerbrechlicher.
Simon Urbanek
Danke Simon. ReferenceClasses war mir erst bekannt, nachdem ich dies gepostet hatte.
Jbryer