投稿者 魔界の仮面弁士  (社会人) 投稿日時 2010/7/4 12:17:22
ByRef にしてしまうと、たとえば As Long な引数に As Integer な変数を渡せなくなるなど、
呼び出し上の不便さも発生しますね。

> VB6のときは、ByRefがディフォルトだったんですね。
VB6 というか、VB1/VB2 の頃の名残です。

VB4以降とそれより前とでは型システムが微妙に異なるのですが、今でいうところのVariant型や
総称Object型を扱う分には、16bit当時は参照渡しの方がパフォーマンスが良かったのです。

しかし、メソッドの呼び出しが単一アプリ内で完結していたころは良かったのですが、機能拡張により
プロセス間通信が行えるようになった後継バージョンにおいては、マーシャリングの手間が
馬鹿にならないケースが増え、特にVB5以降では ByValの方が好ましいとされるようになりました。
(また、ByVal/ByRefの違いというのは、呼び出し側のコードを見ただけでは違いが分からないため、
 カプセル化に際し、コードが分かりにくくなってしまうために非推奨にされたという経緯もあります)

しかし、ByVal/ByRefの省略時の動作を変更してしまうと、互換性上の多大な問題を残すため、
省略時の動作の切り替えは、VB7すなわち.NET 版の登場まで見送られていたというわけです。
# それとて、切り替えには賛否両論あったわけですが。


> 不用意に引数に入れた変数が、いつの間にか値が変っていた、なんて事故を避ける為にか?
もうひとつ、下記のような分かりにくい問題を避ける意図もあります。
http://support.microsoft.com/kb/216481/ja


> 整数配列を引数に入れて、sub内で内容変更させると、
> ByValであっても、変更内容がCall元に戻るのですね。
これは、配列が「参照型」であるためです。
もしも配列の中身を操作するのではなく、subOutArg メソッド内で「aTb = 新しい配列」といった
配列そのものの差し替えを行う場合においては、ByVal と ByRef の差が明確となります。


> VB6では、ByValで配列全体を引数に設定できませんでした。筋が通っていますね。
この違いは、VB6 でも同様です。
http://support.microsoft.com/kb/161308/ja

VB6 以下では配列をByValで渡せませんが、オブジェクト(これも参照型です)を渡した場合には、
今回の件と同様の現象が発生します。たとえば、TextBox をByVal で渡そうと ByRef で渡そうとも、
メソッド内で TextBox の Text プロパティを編集することができます。ただし引数が指し示す実体を
別の TextBox への参照に差し換えようとする場合においては、ByRef でなければなりませんが。


> VBには言語仕様的に変な所もある、という事かな。
VB以外の言語でも同様の動作になりえますよ。

なお、ByRef については、VB6 から変更された点がもう一つあります。
たとえば、Sub Test(ByRef s As String) なメソッドがあり、ここに TextBox1.Text のような
プロパティを渡すとします。この場合、VB6 までは「式」を渡されたものとして扱われ、
Text プロパティの内容までは書き変わらなかったのですが、VB.NET では変更されます。

   Call Test(TextBox1.Text)

Sub Test(ByRef s As String)
    s = "New Text"
End Sub