Short cut: [Prev] [Up] [Next] [Return to Top]

副作用 (1997.Nov.15)

 「関数の副作用」という言葉を知っているだろうか?この業界では:
「余計な副作用がある関数を書いてはいけない」と習うか、
「副作用のある関数を使う場合は注意しろ」とか教えられると思う。

 Lispやった事があるなら絶対に知っているはず。C、Pascalな人も知っている事と思うし、CobolやFortran77な人も……う〜む?
 という訳で念のため書く。

 VBの変数呼び出しにはCall by ValueとCall by Referenceの2通りある事は周知と思う。「値呼び出し」と「参照呼び出し」である。

 書き方では
Function foo (ByVal i As Integer) と
Function bar (i As Integer) の違いとなる。
 引数に変数の値がコピーされるのか、変数自体が渡されるのかの違いである。

 fooの中でiをどんなにいじくろうが、それは単なるコピーなので呼び出した側の変数には何の変化もない。しかし、
 barの中でiをいじると、それは変数そのものなので呼び出した側の変数も変化してしまう。これが副作用である。

 もちろん、副作用をねらってプログラムする事もある。
Function ChgUpper(s As String)
	s = UCase$(s)	 '呼び出し元の変数も大文字になる
	If Len(s) <>  0 Then
		ChgUpper = True
	Else
		ChgUpper = False
	End If
End Sub
 何となくありそうなシチュエーションではなかろうか?

 VBで怖いのは、関数を呼び出す側からはどっちの変数呼び出し方法が使われているか分からないと言う事。

iL = Len(ss)
iP = FuncX(iL)
MsgBox CStr(iL)

 さて。iLの値は何と表示されるでしょう?
 …要するに可読性が低いと言いたいのである。これはVBの言語仕様でしょうがないのだが、困った事だと思う。

 もっとも、FuncX(i+1)とか書いてあれば間違いなく「値呼び出し」と断言できる。
「参照呼び出し」では式を引数にできないからだ。

 そして「値呼び出し」の関数は安心できる。その関数の中で何をやろうと呼び出し元の変数には影響がないから、引数として使った変数を呼び出し後にいくら使い回しても安全。

 VBの組み込み関数の多くは(調べた訳ではないが、全部ではなかろうか?)「値呼び出し」になっているようだ。
 VBのデフォルトの引数定義は「参照呼び出し」だが、問題なければ「値呼び出し」を自分で書く時のデフォルトにしてはどうだろう。できるだけByValを付けて関数を定義するのだ。そうすればうっかり引数を関数内で変更しても上に全く影響がないから、妙なバグり方をさせないで済む。

 自分の影響を必要最小限にする、というのもまたプログラムの基本だし。

#てなこと言いながら自分でもやってないな、これ。次回から気を付けよっと(^^;
@ちなみにマニュアルにもByValを付けることを推奨すると書いてあった

PS. 余談だが、Function ChgUpper()の条件式の書き方として、
(1)
If Len(s) <>0 Then
	ChgUpper = True
Else
	ChgUpper = False
End If

(2)
If Len(s) = 0 Then
	ChgUpper = False
Else
	ChgUpper = True
End If

  どっちが良いでしょう?実は初め(1)の書き方で書き、後で(2)にしたのです。
  どちらも同じという意見もあるでしょうが、If 〜 Then 〜 Else 〜を:
  もし〜なら〜、じゃなかったら〜。と読む時、「〜で『ない』時True」という
  点に引っかかって、これは「〜の時True」が自然だと考えた訳です。

Short cut: [Prev] [Up] [Next] [Return to Top]