web-dev-qa-db-ja.com

Rおよびオブジェクト指向プログラミング

Rでは、何らかの方法でオブジェクト指向プログラミングが非常に可能です。ただし、たとえばPythonとは異なり、オブジェクト指向を実現するには多くの方法があります。

私の質問は:

どのようなmajorの違いが、これらのOO Rプログラミングの方法?

理想的には、ここでの答えは、どのOOプログラミング方法が彼らのニーズに最適であるかを決定しようとするRプログラマーのための参照として役立ちます。

そのため、私は詳細を求め、経験に基づいて客観的な方法で提示され、事実と参照に裏付けられています。明確にするためのボーナスポイントhowこれらのメソッドは、標準OOプラクティスにマップします。

78
Paul Hiemstra

S3クラス

  • 実際にはオブジェクトではなく、より多くの命名規則
  • に基づいて。構文:例印刷の場合、printprint.lmprint.anovaなどを呼び出します。見つからない場合は、print.default

S4クラス

参照クラス

proto

  • ggplot2は元々protoで記述されていましたが、最終的にはS3を使用して書き換えられます。
  • きちんとした概念(クラスではなくプロトタイプ)ですが、実際には扱いにくいようです
  • Ggplot2の次のバージョンは、それから離れているようです
  • 概念と実装の説明

R6クラス

  • 参照
  • S4クラスに依存しません
  • 作成 R6クラスは参照クラスに似ていますが、フィールドとメソッドを分ける必要がなく、フィールドのタイプを指定できない点が異なります。」
33
Ari B. Friedman

3/8/12に編集:以下の回答は、最初に投稿された質問の一部に対応しており、その後削除されています。私の答えのコンテキストを提供するために、以下にコピーしました:

さまざまなOOメソッドを、たとえばで使用されるより標準的なOOメソッドにどのようにマッピングしますか。 JavaまたはPython?


私の貢献は、RのOOメソッドがより標準的なOOメソッドにどのようにマッピングされるかという2番目の質問に関連しています。過去にこれについて考えてきたように、私は何度も何度も2つのパッセージに戻りました。1つはフリードリッヒライシュ、もう1つはジョンチェンバーズです。どちらも、RでのOOのようなプログラミングが他の多くの言語と異なる風味を持っている理由を明確に説明しています。

最初に、フリードリッヒ・ライシュ、「Rパッケージの作成:チュートリアル」( warning:PDF ):

Sは、インタラクティブであり、オブジェクト指向のシステムを備えているため、まれです。クラスの設計は明らかにプログラミングですが、Sをインタラクティブなデータ分析環境として有用にするためには、関数型言語であることは理にかなっています。 C++やJavaクラスおよびメソッド定義のような「実際の」オブジェクト指向プログラミング(OOP)言語では、メソッドとクラスの定義が緊密に結合されているため、メソッドはクラス(およびオブジェクト)の一部です。事前に定義されたクラスのユーザー定義メソッドのような、インクリメンタルでインタラクティブな追加が必要です。これらの追加は、データセットの分析中にコマンドラインプロンプトで実行中であっても、いつでも行うことができます。 Sは、オブジェクト指向とインタラクティブな使用との間で妥協を試みます。妥協は、到達しようとするすべての目標に関して決して最適ではありませんが、実際には驚くほどうまく機能します。

もう1つは、John Chambersの素晴らしい本 「データ分析用ソフトウェア」 からの引用です。 ( 引用文へのリンク ):

OOPプログラミングモデルは、Sおよびその他の関数型言語がクラスとメソッドをサポートしている場合でも、最初の点を除いてすべてS言語とは異なります。 OOPシステムのメソッド定義は、クラスに対してローカルです。メソッドの同じ名前が無関係なクラスの同じことを意味するという要件はありません。対照的に、Rのメソッド定義はクラス定義には存在しません。概念的には、これらは汎用機能に関連付けられています。クラス定義は、直接または継承を通じてメソッド選択を決定する際に入力します。 OOPモデルに慣れているプログラマーは、プログラミングがRに直接転送されないが、そうではないことにイライラしたり混乱したりすることがあります。メソッドの機能的な使用はより複雑ですが、意味のある機能を持つように調整されており、OOPバージョンに減らすことはできません。

19
Josh O'Brien

S3とS4はOOプログラミングの公式の(つまり組み込みの)アプローチです。S3とコンストラクター関数/メソッドに埋め込まれた関数の組み合わせを使用し始めました。私の目標はobject $ 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", "[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]')

このアプローチについて書いたブログ記事へのリンクは次のとおりです。 http://bryer.org/2012/object-oriented-programming-in-r へのコメント、批判、提案を歓迎しますこれが最良のアプローチであるかどうか私は確信していないので、このアプローチ。しかし、私が解決しようとしていた問題についてはうまくいきました。具体的には、makeRパッケージ( http://jbryer.github.com/makeR )の場合、オブジェクトの状態を表すXMLファイルを確認する必要があるため、ユーザーがデータフィールドを直接変更したくない同期を維持します。これは、ユーザーがドキュメントで説明した規則を順守している限り、完全に機能しました。

14
jbryer