関連チケット #41
- ポインタを扱う場面を極力無くす
- 実体オブジェクトのコピーを繰り返すよりも高速
参照型変数を全面的に導入する言語システムは、上記のようなメリットを生じさせることができる。現状のABでは、残念ながらこれらの要望には応えることができない。メソッド内で確保されたオブジェクトを戻り値(実体コピーはNG)として扱いたければ、それをポインタ型にしなければならない。ポインタを活用しない環境を無理やり作り出すと、オブジェクトインスタンスがスタック上のあちらこちらに転がってしまうという、パフォーマンス的にあまりよろしくない状況に陥る恐れさえある。
しかし、いきなり参照型変数を導入するといっても、それがどのレベルのお話なのか、皆目検討もつかない。一般的に、オブジェクト変数すべてが参照型になっている言語は多い(C#/Javaなど…)。それら参照先のオブジェクトは高度なGCによって管理され、プログラマの負担を軽減している。しかしながら、AB5で実装する参照型変数はデフォルトの状態で扱うのが前提ではないことに注目したい。
例えば、ABで "Dim obj As Object" としたら、Object型の静的オブジェクトobjがグローバルまたはローカル領域に出来上がる。これは従来の仕様どおり。
これらの措置は下位互換を重視するのが目的ということもあるが、スコープ単位で生成・破棄が繰り返されるオブジェクトの寿命管理は、コード中のほとんどの箇所で利用したいモデルであることは間違いない。C#やJavaを採用した場合でも、GCが面倒を見てくれるからといってオブジェクトの使用範囲(寿命)を全く無視してコーディングしたほうが良いなどという推奨は誰もしないだろう。
実際問題、ABのデフォルトは値型なので、参照型を多用するようなプログラミングスタイルは推奨されない。もし、GCと組み合わせた参照型を推し進めるのであれば、それは下位互換を捨ててAB6などでやりたい課題である。
ABの参照型変数のモデル
- まずは、GCとの関係は切り離して考える。
- 参照型変数を更に値渡し・参照渡しすることが可能である。生成・破棄のアクションを自らが行わないだけであり、一般的なローカルオブジェクトと扱いは変わらない。
- 関数の戻り値として参照を持たせることができる。
ABの参照型変数の一番のメリットは、静的オブジェクトとの相性が良いことである。静的オブジェクトを参照することもできれば、参照先のインスタンスを静的オブジェクトにコピーすることも可能だ。
それでは、"Function test() As Object" など、関数の戻り値にオブジェクトを指定したときこの戻り値は実態オブジェクトなのか、参照型オブジェクトなのか。。。正解は値型。ABのデフォルトは値型となっているので、参照を返したい場合は別途ByRef指定をしなければならない。
Function test() As Object Dim obj As Object ... Return obj End Function Dim LocalObj As Object LocalObj = test() Dim ByRef refObj = test()
上記のコードは、具体的に言えばtest関数内で定義される静的オブジェクトobjがLocalObjまたはrefObjにコピーされるというコードである。厳密に言えば、refObjが参照しているのは、ヒープ領域に作成されたtest関数内のobjのコピーになる(ヒープ領域に確保された一時オブジェクトはGCによって回収される実装にするため心配はいらない)。
では、オブジェクトインスタンスのコピーを一回の発生させることなく、スマートに関数の戻り値にオブジェクトを指定したいときはどのようにすれば良いのだろう。下記にコードを示す。
Dim globalObj As Object Function test() ByRef As Object Return globalObj End Function Sub main() Dim LocalObj As Object LocalObj = test() Dim ByRef refObj = test() End Sub main()
ここで、LocalObjにはglobalObjの実体がコピーされる。 そして、refObjのほうは、一回もオブジェクトインスタンスのコピーが発生することなく、globalObjを参照することになる。
ByRef修飾子の活用範囲
今までは参照型パラメータのみに指定可能だったByRefが関数の戻り値やDimステートメントの修飾子として利用できるようになる。