`getter` とか `setter` ってなんや?

なんなんでしょうね.


別に深い理解を目指すとかいうものではなく,ヒウィッヒヒーでちょうど getter について何か言ってたような言ってなかったような感じのツイートを見かけて (内容は忘れました),「よく見たらちょい不思議かも」ってのを思いついた日記になります.

オブジェクト指向

皆大好きオブジェクト指向.これに乗っかっていればイケイケプログラミングができるとされていたりいなかったりする.

こいつらを「見て」みて「自分がどう感じるか」について焦点を当てて考えてみた感じ.

プロパティについて

これは綺麗に読むことができる.大体どの言語でも,obj.property_name でアクセスができたりする.

len = a.length

これはそのまま

len is now a's length

のように読めて,まあ比較的自然に所有格か何かっぽい感じがする.

これはオブジェクトに限らず,構造体みたいなものでもこういう感じで書くものなので,オブジェクト指向より前から人々が自然であるとして作ったものなんだと思う.

メソッドについて

これが焦点.例えば次のような疑似コード片を書いてみる.

person p ("Tom");
std::cout << p.greet () << std::endl;
// output: Hi! I'm Tom!

これは恐らくよく見かけるオブジェクト指向っぽいとされるコードの例だと思う.オブジェクト指向は気持ち良く挨拶できる魔法のパラダイムであることが伺える.

このコードは見た感じでは p が主語になっていて,メソッドが動詞みたいなもんなんかなあって思える見た目をしている.

ところで,よく用いられるパターンとして,gettersetter なるものがある.らしい.雰囲気でコードを書いているのでよく知らない.

class SomeObject {
  private int a;
  public int getA() {
    return a;
  }
  public void setA(int newA) {
    a = newA;
  }
}

こんな感じのパターンってよく紹介されている.多分.

メソッドとして定義されているので単なる代入や読み出しだけじゃなくて色々モノを仕込めるみたいな.

これで安全性を確かめるみたいな話を仕込めばプロパティを安全に読み書きできるようになるみたいなことなんだと思う.とてもよいことですね.

さて,実際にこういう系のモノを使ったコードがどんな感じになるかっていうと,こんな具合.

const t = new TextArea();
t.setEditable(false);
t.show();
console.log(t.getPosition());

うん,なんかありそうなコードになった.

この場合,個人的によく考えたら謎っぽいのが t.setEditable(false); の主語って何ってところなんですね.

見た目から平叙文に直すと,こんな感じになる.

(A contextual subject) sets 'editable' of t as false
t shows itself
(A contextual subject) gets 'position' of t

オッ

さっきまでとは少し雰囲気が違って,明らかにメソッドなのに主語がそのオブジェクトっぽくないところがある.なんだよ文脈上の主語って.誰だお前.いやまあ 8 割くらい自分だけども.

なんか主語とかがすごいことになってるよね.

無理矢理 t を主語にするなら次のような感じになると思う.

t recieves false and sets it as its 'editable'
...
t let (us) know its 'position'

そうそうこんな感じ.

何か色々捻れてる気がする.

オブジェクト指向カプセル化うんたらの話からすると,この gettersetter もオブジェクトに隠された文脈 (まあ多分クラス定義とかの文脈) に存在する関数ってだけで,主語の話はどこにもないし,主語にするならオブジェクト自身であるというより「隠された文脈の中での主語」って具合であるところなんでしょう.

それでも結局コイツらはインターフェイスとして外に露出しているわけで,特に gettersetter は確実にその意図があって設計されているんすよね.見た目の主語がちんぷんかんぷんな印象を受けました.今までよく考えてなかったので昨日初めてそう思ったんですけど.

自分はこういうのは慣習に則るのが正解だと思っているので,特に反旗を翻すような実装例を提唱する気はないけど,よく考えてみると「おお,なんかちょっとだけ思ってたのと違うじゃん」ってなりますよね.なりました.

そもそものメソッド

メソッドって何?っていうのは辞書引くなり wikipedia 見るなりすればよく分かると思うので割愛します.ちなみに自分はよく分かってないです.

まあ書き方なんですけど,Ruby ではこう.

class ClassA
  # ...
  def method_a arg
    # ...
  end
end

b = ClassA.new
puts b.method_a 7

フツーっすね.とても良いことだと思います.これを見ても「ああ Ruby だ」ってなる感じですね.

Python だと多分こんな感じだった気がする.

# ...
def kick(self, target):
    # ...

ここで明示的に第一引数に self が出てきています.使うときは次みたいな.

a_friend_of_mine.kick(me)

定義したときには存在した self がカッコの中には存在しないですね.まあレシーバなんすけど.

他には,クラスが存在しない Go だとこんな感じでメソッドを書くはず.

(p *Person) greet(statement string) {
  fmt.Printf("I'm %s! %s!\n", p.Name, statement)
}

ここで明らかなように,メソッドを呼ばれるレシーバは第一引数,あるいは特別な引数として存在している感じ.

Lua にもクラスがなく,テーブルやら何やらの仕組みでメソッドっぽいものを書いたりするらしいですが,シンタックスシュガーとして次のような話があるらしい (書いたことはないですが).

# 下のふたつは大体同じ (厳密には評価の回数が違うとかなんとか)
a:move_to (pos)
a.move_to (a, pos)

まあ雰囲気は感じ取れますね.

C 言語でもそれっぽいものを書くことができて,次のようなものを見たことがある気がします (多分).

void window_move_to (WINDOW *w, int x, int y) {
  // ...
}

ここまで来ると「特別な第一引数がレシーバ」ってことがなんとなくわかる.クラス云々や構文的にレシーバであることを示す要素がなくてもそれっぽいです.

こういうのを見るとレシーバに対して,その情報を引き出して何かしたり,直接働きかけるものっていう感じがしてきました.あなたがそう思わなくても僕はそう感じています.

これを上手い具合に隠蔽してやるとあたかもオブジェクト自身が文脈を持って動いたり相互作用したりする世界になりそうっていう.

まあそうすると結局レシーバはメソッド定義時点では目的語で,外から見ると主語っぽい感じになってると嬉しいってとこなんすかね.

難しいことはよくわからないので賢い人に色々教えていただきたいです.よろしくお願いします.

総括

getter とか setter ってなんや?