Jewel-mmo開発日記

RubyでMMORPGを作る過程を記録する日記。 Yokohama.rb 発起人。
2010-11-09

とあるスクリプト言語のオブジェクト指向への道のり

職場に独自の小さなスクリプト言語とそれを動かすVMがある。

ゲームの組み込みに使われているんだけど、VMで動作する特性上使い勝手がよく、 文法もJavaScriptによく似ていて取っ付き易い。

そして素晴らしいことに要望を出すとすぐに改善されるのだ。 先日は0を真に変えてもらったりもした(偽になるのはnilとfalseだけとなった)。

まだ配列とハッシュがないのだけど、これも近々サポートされることになりそう。 そこで、その先にある(と思われる)オブジェクト指向言語化について考えてみた。

次の3ステップでオブジェクト指向化できないかな? ツッコミどころはありそうだけど、たたき台ということで。

※ここから先興味のある方はJavaScriptをイメージしてもらうといいかも

その1。「値.関数名()」と書いたらレシーバを第1引数として渡す

次のようにメンバ変数(ハッシュ)に関数を代入して呼び出すと、 強制的に第1引数に自分自身が渡される。

value.method = function(self, a) { ... }
value.method(a)

考えたのだけどハッシュに関数を入れた場合、 selfが欲しいケースの方が断然多いんじゃないかな。

だたしselfが不要な場合もあるかもしれないので、 そのときは次ように「!」を使って呼び出す方法も用意しておく。

value!method(value, a)

これは負荷対策以外に意味はないけど。

その2。メンバ関数(インスタンスメソッド)の定義方法

関数側も引数の定義でselfと毎回記述するのはウザイ。

function method(self, a) {
  puts(self.keys)
}

そこで次のように書けたらどうだろうか。

function method(@, a) {
  puts(@keys)
}

関数内の@は自動的に「self.」に置き換えられる。

関数定義は次のような形の方がよりいいかな。

function @method(a) {
  puts(@keys)
}

なんかインスタンスメソッドを定義しているように見えていい感じだ。

しかしどうせならclassキーワードを導入したらどうだろう。

class Klass {
  function method(a) {
    puts(@keys)
    @method2()
  }
  function method2() {
  }
}

おぉこれでいいじゃないか!

もちろん@は「self.」に展開されるだけなので、上の@method2()のように関数呼び出しにも使える。

さてここまで来ればオブジェクト指向言語まであと一歩。

その3。ミックスイン

Klassクラスを次のように定義したとする。

class Klass {
  function method1() { ... }
  function method2() { ... }
}

これをオブジェクト(ハッシュオブジェクト)に関連付けなくてはいけない。 ここでmixinという新たな仕組みを用意する。

obj = {}
mixin(obj, Klass)
obj.method1()
obj.method2()

mixinはKlassクラスが持っている関数のポインタそれぞれをobjのメンバに代入する関数だ。 イメージとしては次のような感じ。

obj.method1 = Klass.method1
obj.method2 = Klass.method2

あくまで静的にメソッド呼び出しを解決したいので、 mixinするクラスに階層などはない。 同じ関数名があればあとからmixinしたものが優先される。

class型という新しい値が必要になっちゃうかな。

ちなみにmixinは次のように書けた方がいいかもしれない。

obj = {}
obj.mixin(Klass)

でもここまできたらこう書きたいよね!

obj = new(Klass)

またはこうかな。

obj = Klass.new