ByValとByRef

Function MyFunc(A As Integer) As Integer

このように関数を宣言したとします。
このとき引数のAの前にByValかByRefをつけることができるのですが、どちらの方が良いのでしょう。

まず簡単な方のByValによる値渡しを見てみましょう。
値渡しは、文字通り、変数の値をそのまま渡します。
関数に渡されるのはただの値でしかないのでこの場合は関数に与えられた変数の値を変えるすべがありません。
ただし、関数は与えられた値をそのまま使うことができるのでByRefに比べて高速です。

次に、省略した時と同じByRefによる参照渡しを見てみましょう。
参照渡しなので、当然何かを参照して渡します。
その何かとは変数のアドレスです。
早い話が、変数の在り処を関数に教えるわけです。
そして関数はその住所を頼りにして変数を探し、利用するわけです。
そんなまどろっこしい方法を使って変数の値を知らなくとも値渡しを使えば一発でわかってしまうのでByValの方が速くて良さそうな気がしますが、どうしてByRefを使うのでしょうか。
関数側は変数の住所を知っているわけです。
探しに行って値を調べられるのならば、逆にそこへ行って変数の値を変更することもできるのです。


これを人間の世界に例えてみると、こうなります。

Function 変な顔に整形する(ByVal 被害者 As 人) As Integer
の場合、被害者に私を設定しても、関数には私の値(情報)しか渡らないので、私がかっこいい顔をしているということはすぐにわかっても、整形して変な顔にすることはできません。

Function 変な顔に整形する(ByRef 被害者 As 人) As Integer
の場合は、被害者を私に設定するとこうなります。
流石に私本人が渡されるわけではありませんが、関数は住所を知ることができます。
そして関数は私の家を訪問して私がどんなにかっこいい人間であるかを知り、整形して変な顔にすることができるのです。


03/05/14追加分

実際に速度を比較してみました。

Sub ByRefFunc(ByRef a As Integer)……0.155マイクロ秒
Sub ByValFunc(ByVal a As Integer)……0.148マイクロ秒

また、値を直接渡せない文字列型、Variant型などではこれが当てはまらないようです。
実際、次の関数に"文字"を渡すと次のようになりました。

Sub ByRefFunc(ByRef a As String)……0.30マイクロ秒
Sub ByValFunc(ByVal a As String)……0.37マイクロ秒


03/06/10追加分

例によって人間の世界に例えてみます。

Function 参考書籍を見る(ByVal 参考書籍 As 本) As Integer
これは、いわば本の内容を読み上げてもらってから、その内容を覚えておいてそれを使っているのと同じです。
こんなもの人間に覚えきれるはずもありませんし、何より時間がかかります。

Function 参考書籍を見る(ByRef 参考書籍 As 本) As Integer
この場合は、「○○の本を参照のこと」と言われたようなものです。
図書館まで行って借りてくるのには時間がかかりますが、読み上げてもらうのに比べればまだましです。
ただし、本を汚してしまう可能性があるという問題があります。