プロトタイプオブジェクトモデルをSchemeで!(失敗編)
JavaScriptのプロトタイプオブジェクトモデルを妄想しているうちに、自己満足Scheme実装で作れるんじゃないかと考えはじめ、ちょこっと作って見ましたが、あえなく失敗しました。
ここでいう自己満足Scheme実装では
exp1.exp2
と書くと、exp1を評価して、これがクロージャだったりすると、このクロージャが捕まえている環境でexp2を評価します。
Schemeとしてはかなり変態的なシンタックスですね。
このあたりで書いてます。
http://d.hatena.ne.jp/ujip/20070321
この中で書いている「実際のプログラム」で、クラスからオブジェクトを生成していますが、クラスでいうところのメソッドがオブジェクトごとに生成されてしまうんですね。
だから、クラスにメソッドを追加しても、すでに生成されたオブジェクトには追加したメソッドが利用できないんです。
JavaScriptのプロトタイプオブジェクトモデルは、プロトタイプオブジェクトのプロパティが、このプロトタイプと関係しているコンストラクタ関数で生成されたオブジェクトで共有されるんですね。
おおお!
とおもって、これを自己満足エセScheme処理系で作れないかと妄想したわけですが、ダメですね・・・
だめだったソース。
(define nil '()) (define make-constructor cons) (define constructor-of-prototype-object car) (define constructor-of-initializer cdr) (define (new constructor . args) (let ((this (constructor-of-prototype-object constructor).(let ((nil nil)) (lambda () nil)))) (apply (constructor-of-initializer constructor) this args) this ) ) (define object (lambda () nil)) ;TODO ;Line-Prototypeコンストラクタで定義した関数から、 ;Lineコンストラクタ関数で定義したシンボルstart,endを参照するには ;どうしたらいいのか。 (define Line-Prototype (make-constructor object (lambda (this) this.(define (setstart! newstart) (set! start newstart)) this.(define (setend! newend) (set! end newend)) this.(define (length) (abs (- end start))) ) ) ) (define line-prototype-object (new Line-Prototype)) (define Line (make-constructor line-prototype-object (lambda (this s e) this.(define start 0) this.(define end 0) (this.setstart! s) (this.setend! e)) ) )
make-constructor関数でコンストラクタ関数を生成。
プロトタイプオブジェクトとイニシャライザ(1引数のクロージャ)を渡してあげます。
new関数は、make-constructor関数で生成したコンストラクタ関数でオブジェクトを生成。
オブジェクトはコンストラクタ関数生成時に渡したイニシャライザでイニシャライズすると。
で、生成されたオブジェクトはコンストラクタ関数生成時に渡したプロトタイプオブジェクトにリンクします。
でも、これは失敗作。
(define line1 (new Line 3 5))
などとすると、イニシャライザ内(this.setstart! s)実行時にエラー。
this.setstart!はline-prototype-object内で定義されていて、setstart!内ではstart変数を参照使用しているのですが、これはsetstart!が定義されている環境には無く、この子環境(?)内にあるんです。
クロージャの環境を操作することでプロトタイプオブジェクトモデルが実現できるんじゃないかと言うもくろみは失敗です。
もすこし、精進します。
そんなことより、JavaScriptの勉強を続けましょう>俺。