C/C++/C#言語の副作用完了点を、Visual Basic .NETで記述する際の注意点
自分は、仕事柄 C言語系に慣れている人でして、以下のような記述を(無意識に)するケースが多いんですね。
char* strMessage = NULL; ... if((strMessage != NULL) && (strlen(strMessage) > 0)) ...
ここで、上のif文の「&&」は「副作用完了点」と呼び、左の式が真にならないと、右の式が実行されない訳です。(詳しくは、C言語FAQやK&R聖典を読んで下さい)
C言語上がりの自分がBasic言語に触れて、驚いた事の一つに、上の記述が通用しなかった点なんですね。
Dim strMessage As String = Nothing ... If (strMessage IsNot Nothing) And (strMessage.Length > 0) Then ...
はい、こんな書き方ではエラーが発生します。
少なくとも、以下のように書く必要があります。
If strMessage IsNot Nothing Then If strMessage.Length > 0 Then ...
驚いたものの、引っかかった当時「Basicって どういう評価順番なのかなぁ」と思いつつ、特に突っ込んで調べもせず、そのまま放っておいてました。(ダメ人間ですね)
で、先日マイクロソフトさんの登録されているMSKBを ぼ〜っと眺めていたら、以下の記事が。
- Visual Basic での "ショートサーキット" 評価の説明
http://support.microsoft.com/kb/817250/ja
Visual Basic 2005 または Visual Basic .NET では、論理 AND 式および論理 OR 式のオペランドは、1 つ目のオペランドの結果に関係なく、2 つ目も評価されます。
...
ただし、Visual Basic 2005 または Visual Basic .NET には、新しい 2 つの演算子 (AndAlso 演算子および OrElse 演算子) があります。これらの演算子を、それぞれ論理 AND 演算子および論理 OR 演算子の代わりに使用できます。これらの演算子を使用すると、Visual Basic .NET で "ショートサーキット" 評価を行うことができます。
えぇぇえ??そうだったの?
この「ショートサーキット評価」って要するに、「副作用完了点」と同じ事だよね?
という訳で、早速検証。
Imports CON = System.Console Function func(ByVal msg As String) As String CON.WriteLine("call func({0})", msg) Return msg End Function Sub Main() CON.WriteLine("普通のAndテスト") If (func("左辺") <> "左辺") And (func("右辺") <> "右辺") Then CON.WriteLine("両方一致") CON.WriteLine("AndAlsoテスト") If (func("左辺") <> "左辺") AndAlso (func("右辺") <> "右辺") Then CON.WriteLine("両方一致") CON.WriteLine("IIfテスト") CON.WriteLine("IIf = {0}", IIf(True, func("TRUE"), func("FALSE"))) End Sub
上のコードを実行すると、以下のようになります。
普通のAndテスト call func(左辺) call func(右辺) AndAlsoテスト call func(左辺) IIfテスト call func(TRUE) call func(FALSE) IIf = TRUE
なるほど。確かに「And演算子」を使わず「AndAlso演算子」を使うと、左辺のみ評価可能ですね。
ちなみに、下のIIf関数の例は、三項演算子の代用として時折使うので、念の為 動作を確認してみたんですね。
案の定、ただの関数なので、「引数に記述した関数は当然実行」されます。
ちなみに、C言語系であるC#で記述すると、以下のようになります。
using CON = System.Console; string func(string msg) { CON.WriteLine("call func({0})", msg); return msg; } public void test() { CON.WriteLine("andテスト"); if ((func("左辺") != "左辺") && (func("右辺") != "右辺")) CON.WriteLine("両方一致"); CON.WriteLine("三項演算子"); CON.WriteLine(" = {0}", (true ? func("true") : func("false"))); }
上のコードを実行すると、以下のようになります。
andテスト call func(左辺) 三項演算子 call func(true) = true
よしよし、C言語と同じ動きです。
更に、Pythonで記述すると、以下のようになります。
# -*- encoding: shift-jis -*- def func(msg): print "call func(%s)" % msg return msg print "andテスト" if (func("左辺") != "左辺") and (func("右辺") != "右辺"): print "両方一致" print "Python2.5から使える三項演算子" ret = func("true") if True else func("false") print ret
上のコードを実行すると、以下のようになります。
andテスト call func(左辺) Python2.5から使える三項演算子 call func(true) true
とはいえ
言語の期待する書き方に合わせた方が楽ですよね。
変にアクロバットな書き方は、リスクが高いので気をつけましょうという事です。(これがオチ)