今日のニワン語メモ

ニワン語 de オブジェクト指向
・・・いえ、元々ニワン語はオブジェクト指向(もどき)なんですが、ガチでオブジェクト指向する――具体的にはクラスを定義してインスタンスを生成する――やり方を開発したので書いておきます。
※言語仕様上厳密には行えないのであくまで擬似的なものであることはご了承ください。
※説明上改行していますが実際は一行で書きます。

■クラス定義

0::/Person = Object.clone
0::/Person.def(setBody(body), self.body = body)
0::/Person.def(setShadow(shadow), self.shadow = shadow)
0::/Person.def(init(name), self.name = name; self.age = 0; body.visible = shadow.visible = false)
0::/Person.def(getOlder(), age++)
0::/Person.def(display(x, y), body.text = shadow.text = 'name:' + name + ',age:' + age; 
               body.x = x; shadow.x = x + 1; body.y = y; shadow.y = y + 1;
               body.color = 0xffffff; shadow.color = 0x000000
               body.visible = shadow.visible = true)

インスタンス

0.00::/person = Person.clone
0.01::/person.setShadow(drawText(''))
0.02::/person.setBody(drawText(''))
0.03::/person.init('青野はるみ')
0.04::/person.getOlder()
0.05::/person.display(100, 100)

→(100, 100)の位置に「name:青野はるみ,age:1」と影付き文字で出力される

注意点↓
1.クラス定義で、フィールドを宣言しない
オブジェクト指向馴染みのある方だと、例えば以下のようにしたくなるかもしれません。(特にソースにコメントを付けている場合)

0::/Person = Object.clone
0::/Person.name = ''
0::/Person.age = 0
0::/Person.def(setBody(body), self.body = body)
0::/Person.def(setShadow(shadow), self.shadow = shadow)
0::/Person.def(init(name), self.name = name; age = 0; body.visible = shadow.visible = false)
0::/Person.def(getOlder(), age++)
0::/Person.def(display(x, y), body.text = shadow.text = 'name:' + name + ',age:' + age; 
               body.x = x; shadow.x = x + 1; body.y = y; shadow.y = y + 1;
               body.color = 0xffffff; shadow.color = 0x000000
               body.visible = shadow.visible = true)

これはNGです。
なぜなら、clone命令はフィールドの中身を複製しないからです。いわゆる基本型の変数でも!(←重要)
そのため、上記のPersonクラスのインスタンスを複数、例えばperson1とperson2を作ったとして、person1の名前を'青野はるみ'、年齢を1にすると、person2の名前も'青野はるみ'、年齢も1になります。(内部的には全ての値は参照型として扱われているのでしょうか?)
そこで、フィールドへの値はclone後にメソッドに引数として渡してから代入するか、メソッド内で生成した値を代入するかする必要があります。

2.描画オブジェクトは外部渡し
上の記述はもしかしたらこう書きたくなるかもしれません。

0::/Person = Object.clone
0::/Person.def(init(name), self.shadow = drawText(''); self.body = drawText('');
               self.name = name; self.age = 0; body.visible = shadow.visible = false)
0::/Person.def(getOlder(), age++)
0::/Person.def(display(x, y), body.text = shadow.text = 'name:' + name + ',age:' + age; 
               body.x = x; shadow.x = x + 1; body.y = y; shadow.y = y + 1;
               body.color = 0xffffff; shadow.color = 0x000000
               body.visible = shadow.visible = true)

インスタンス化の時の手間も省け、いかにもスマートですがこれもNGです。
なぜなら、ニワン語では描画オブジェクトの生成において、コード上の生成順と実際の生成順が一致しないからです。実行する度に順番が変わってしまうため、今回の例で行くと、影が下に描写されたり上に描写されたりと不安定な動きをしてしまいます。
※ちなみに描画オブジェクトの生成以外はちゃんとコード上の順番通り実行されます。おそらく描画オブジェクトの生成はその命令が別の管理下においてプールされ、その管理者がプール分を順番を保証せずに生成するのではないかと推察します。
この生成順を保証するには、命令を出す時間(スクリプトを書く際に一番左に書く時間)をずらすしかありません。

0.00::/a = drawText(''); b = drawText('')
→生成順が保証されない
0.00::/a = drawText('')
0.00::/b = drawText('')
→生成順が保証されない
0.00::/a = drawText('')
0.01::/b = drawText('')
→生成順が保証される(a→bの順)

3.描画オブジェクトの外部渡しの仕方
オブジェクト指向馴染みのある方だと、コンストラクタ(init())の前にsetTextObj()を呼ぶのが気に入らないので、以下のようにしたくなるかもしれません。

0::/Person = Object.clone
0::/Person.def(init(body, shadow, name), self.body = body; self.shadow = shadow; 
               self.name = name; self.age = 0; self.body.visible = self.shadow.visible = false)
0::/Person.def(getOlder(), age++)
0::/Person.def(display(x, y), body.text = shadow.text = 'name:' + name + ',age:' + age; 
               body.x = x; shadow.x = x + 1; body.y = y; shadow.y = y + 1;
               body.color = 0xffffff; shadow.color = 0x000000
               body.visible = shadow.visible = true)

これはありですが微妙です。
これをした場合、インスタンス化の際に

0.00::/person = Person.clone
0.01::/shadow = drawText('')
0.02::/body = drawText('')
0.03::/person.init(body, shadow, '青野はるみ')
0.04::/person.getOlder()
0.05::/person.display(100, 100)

と無駄に変数を用意する必要があります。そこに抵抗がなければかまいません。
ーーと書くと、こうすればいいって思うかもしれません。

0.00::/person = Person.clone
0.01::/person.init(drawText(''), drawText(''), '青野はるみ')
0.02::/person.getOlder()
0.03::/person.display(100, 100)

これがNGなのは前述の通りですね?