R をオブジェクト指向風に使ってみる

Rでは S4 メソッドでオブジェクト指向は行えるけど、手軽には使いにくい。
そこで、クロージャーと eval を使ってオブジェクト指向風なことをやってみる。
…というのは建前で、s「substitute と eval 使えばクロージャー内の関数呼べそう」と思ったから試してみただけ。

cls <- function(x, y) {
	show <- function() { cat("x:", x, ", y:", y, "\n") }
	add_x <- function(v) { x <<- x + v ; exe}
	add_y <- function(v) { y <<- y + v ; exe}
	a <- function(...) UseMethod("a")
	a.default <- function(v) { print("default") }
	a.matrix <- function(m) { print("matrix") }
	exe <- function(e){ eval(substitute(e)) }

	exe
}

#インスタンス生成
instance <- cls(3, 4)
# show() メソッド呼び出し
instance(show())
# x の値を返す
instance(x)
# x の値変更
instance(x <<- 10)
# 環境経由の操作
environment(instance)$x
environment(instance)$x <- 11
# メソッドを連続して呼び出し
instance(add_x(3))(add_y(1))(show())
# 引数の型による多態性
m <- matrix(1:3)
instance(a(m)) # a.matrix の呼び出し
instance(a(1:3)) # a.default の呼び出し
# Ruby の特異メソッド風に inc_x を追加
evalq(inc_x <- function(){x <<- x + 1; exe}, envir=environment(instance))
instance(inc_x())(show())

# サブクラス
cls2 <- function(x,y,z) {
	# スーパークラスの定義をここで再定義
	super <- environment(cls(x,y))
	for(v in ls(super)) {
		val <- get(v, super)
		environment(val) <- environment()
		assign(v, val)
	}

	# サブクラスでの定義
	show <- function() { cat("x:", x, ", y:", y, ", z: ", z,"\n") }
	# スーパークラスの同名のメソッド定義を利用するなら、こんな風にも書ける
	# show <- (function(){ show<-show; function(){ show(); cat("z: ", z,"\n")} })()
	add_z <- function(v) { z <<- z + v ; exe}

	exe
}

instance2 <- cls2(1,4,3)
instance2(show())
instance2(x <<- 10)
instance2(add_x(3))(add_y(1))(show())

カプセル化は protect なメソッドぐらいしかできそうにないので(めんどくさいから)やめとく。
サブクラス化の無駄が多い気がするな。再定義の部分どうにかならんかな?

    super <- environment(cls(x,y))
	e <- environment()
	parent.env(super) <- parent.env(e)
	parent.env(e) <- super

とやると、ある程度うまくいくけど、instance2(add_x(3))(show()) の show はスーパークラスの方が呼び出されてしまうし…。
まあ、実際に使うことはないだろうから、どうでもいいんだが。