|
|
連載
改訂版
プロフェッショナルVB.NETプログラミング
Chapter 04 演算子と関数の変化
株式会社ピーデー
川俣 晶
2004/04/01 |
|
|
VB 6には、Eqv演算子とImp演算子という演算子があった。これは、はるか遠い祖先のBASICから受け継いだ演算子で歴史は長い。しかし、これらの演算子が有効に活用された事例があるかというと、残念ながら筆者はそのようなものを知らない。ほかの演算子の組み合わせでも容易に実現できるものであり、なくてもあまり問題にならないのではないかと思っていたが、とうとうVB.NETでなくなってしまった。
リスト4-10は、VB 6でこれらの演算子を使った例である。
1: Private Sub Form_Load()
2: For i = -1 To 0
3: For j = -1 To 0
4: Debug.Print i; " Eqv "; j; "="; i Eqv j
5: Next
6: Next
7: For i = -1 To 0
8: For j = -1 To 0
9: Debug.Print i; " Imp "; j; "="; i Imp j
10: Next
11: Next
12: End Sub
|
|
リスト4-10 Eqv演算子とImp演算子を使用したプログラム
|
これを実行すると以下のようになる。
1: -1 Eqv -1 =-1
2: -1 Eqv 0 = 0
3: 0 Eqv -1 = 0
4: 0 Eqv 0 =-1
5: -1 Imp -1 =-1
6: -1 Imp 0 = 0
7: 0 Imp -1 =-1
8: 0 Imp 0 =-1
|
|
リスト4-11 リスト4-10の実行結果
|
これと同じ結果が得られるようにVB.NETで記述したプログラムが、リスト4-12である。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim i, j As Integer
3: For i = -1 To 0
4: For j = -1 To 0
5: Trace.WriteLine(i & " Eqv " & j & "=" & Not (i Xor j))
6: Next
7: Next
8: For i = -1 To 0
9: For j = -1 To 0
10: Trace.WriteLine(i & " Imp " & j & "=" & ((Not i) Or j))
11: Next
12: Next
13: End Sub
|
|
リスト4-12 リスト4-10と同じ結果を得るVB.NETのプログラム
|
これを実行すると次のようになる。
1: -1 Eqv -1=-1
2: -1 Eqv 0=0
3: 0 Eqv -1=0
4: 0 Eqv 0=-1
5: -1 Imp -1=-1
6: -1 Imp 0=0
7: 0 Imp -1=-1
8: 0 Imp 0=-1
|
|
リスト4-13 リスト4-12の実行結果
|
見てのとおり、Not、Xor、Orなどを組み合わせるだけで等価の結果が得られる。
Eqvに関しては、このプログラムのように処理せず、「=」演算子で代用できるケースも多いだろう。Boolean値が同じかどうかを調べるという動作であれば、「=」演算子でも同じことが実現されるからだ。ただし、演算子の優先順位が違うので、演算子を置き換える際は注意が必要である。同じ順番で演算させるために、必要に応じて括弧などを補おう。
VB.NETには、効率よくAndやOrを含む条件判断を行うAndAlso演算子と、OrElse演算子が追加されている。この2つの演算子は、ショートサーキット演算子と呼ばれる。使わなくてもプログラムは作成可能だが、うまく使えば処理速度を向上できる可能性がある。C/C++/Java/C#をご存じの方は、「&&」や「||」に相当するものだといえばすぐに分かるだろう。まず、VB 6で、普通にOrとAndを使用したサンプル・プログラムを見ていただきたい(リスト4-14)。
1: Private Function DummySearch(ByVal val As Boolean) As Boolean
2: Debug.Print "時間のかかる検索処理を行っています。"
3: DummySearch = val
4: End Function
5:
6: Private Sub Form_Load()
7: If DummySearch(False) And DummySearch(True) Then
8: Debug.Print "第1の条件は満たされています。"
9: Else
10: Debug.Print "第1の条件は満たされていません。"
11: End If
12: If DummySearch(True) Or DummySearch(False) Then
13: Debug.Print "第2の条件は満たされています。"
14: Else
15: Debug.Print "第2の条件は満たされていません。"
16: End If
17: End Sub
|
|
リスト4-14 OrとAndを使用したプログラム
|
これを実行すると以下のようになる。なお“時間のかかる検索処理”は、実際には行われていないが、それが行われていると想像していただきたい。
1: 時間のかかる検索処理を行っています。
2: 時間のかかる検索処理を行っています。
3: 第1の条件は満たされていません。
4: 時間のかかる検索処理を行っています。
5: 時間のかかる検索処理を行っています。
6: 第2の条件は満たされています。
|
|
リスト4-15 リスト4-14の実行結果
|
さて、これをVB.NETで表現したのがリスト4-16である。そのままAndとOrを使っても動作するが、ここではAndAlsoとOrElseに置き換えてみた。
1: Private Function DummySearch(ByVal val As Boolean) As Boolean
2: Trace.WriteLine("時間のかかる検索処理を行っています。")
3: DummySearch = val
4: End Function
5:
6: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
7: If DummySearch(False) AndAlso DummySearch(True) Then
8: Trace.WriteLine("第1の条件は満たされています。")
9: Else
10: Trace.WriteLine("第1の条件は満たされていません。")
11: End If
12: If DummySearch(True) OrElse DummySearch(False) Then
13: Trace.WriteLine("第2の条件は満たされています。")
14: Else
15: Trace.WriteLine("第2の条件は満たされていません。")
16: End If
17: End Sub
|
|
リスト4-16 AndAlsoとOrElseを使用したVB.NETのプログラム
|
これを実行すると以下のようになる。
1: 時間のかかる検索処理を行っています。
2: 第1の条件は満たされていません。
3: 時間のかかる検索処理を行っています。
4: 第2の条件は満たされています。
|
|
リスト4-17 リスト4-16の実行結果
|
見て分かるとおり、VB 6のサンプルでは検索を4回行っているが、VB.NETサンプルでは2回しか検索を行っていない。これは、演算子の手前の式を計算するだけで結果が決まってしまう場合、演算子の後ろの式は計算しないという機能によるものだ。例えば「条件A Or 条件B」というとき、条件AがTrueなら、条件BがTrueでもFalseでも、式全体は必ずTrueになるので、条件Bの計算を省いても条件判断の結果は同じである。同様に「条件A And 条件B」というとき、条件AがFalseなら、条件BがTrueでもFalseでも、式全体は必ずFalseになり、条件Bの計算を省くことができる。必要な計算を減らすことで、うまく活用すれば性能アップになる。
しかし、副作用を期待した計算式を使う場合は要注意である。副作用とは、値を計算するほかに行われる、変数の値を書き換えるなどの動作をいう。例えば、このサンプル・プログラムでいえば、文字列を出力することが副作用である。AndとOrをAndAlsoとOrElseに置き換えると、計算されない式に含まれる副作用は発生しなくなるため、動作が変わってしまう。AndとOrをAndAlsoとOrElseに書き換える場合は、式に副作用が含まれているか、よくチェックしよう。
VB 6には、文字列関連の関数に2つのバージョンを持つものがあった。例えば、Chr関数とChr$関数は別個の関数である。“$”の付くものは文字列型を扱い、“$”の付かないものはVariant型を扱う。この結果、文字列ではないデータを扱ったときに挙動が異なる場合があった。リスト4-18はこのような関数の一例として、Left関数とLeft$関数を扱った例である。
1: Private Sub Form_Load()
2: Dim v As Variant, r As Variant
3: v = Null
4: r = Left(v, 3)
5: Debug.Print TypeName(r)
6: v = "ABCDEF"
7: r = Left$(v, 3)
8: Debug.Print TypeName(r)
9: End Sub
|
|
リスト4-18 Left関数とLeft$関数を使用したプログラム
|
これを実行すると以下のようになる。
|
リスト4-19 リスト4-18の実行結果
|
Left関数にNull値を渡すことは合法で、結果はNull値になる。しかし、Left$関数にNull値を渡すことはできない。
これをVB.NET用に書き換えたのがリスト4-20である。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim v As Object, r As Object
3: v = Nothing
4: r = Microsoft.VisualBasic.Left(v, 3)
5: Trace.WriteLine(TypeName(r))
6: v = "ABCDEF"
7: r = Microsoft.VisualBasic.Left$(v, 3)
8: Trace.WriteLine(TypeName(r))
9: End Sub
|
|
リスト4-20 リスト4-18をVB.NETで書き換えたプログラム
|
これを実行すると以下のようになる。
|
リスト4-21 リスト4-20の実行結果
|
VariantがObjectになる理由については、VariantとObjectを参照してほしい。NullがNothingになるのは、VB 6からVB.NETへの構文の変更点である。さて肝心の結果だが、VB 6の場合とは異なっていることが分かるだろう。VB 6では2種類あった文字列関数は、VB.NETでは1種類しか存在しない。Variant型を返す関数は存在しないため、Left関数の結果は常に文字列になる。構文的にLeftのほかにLeft$という名前を記述することは可能だが、これは型指定文字としての$記号が付加されているだけで、別の関数の呼び出しになるわけではない(なお、Leftというキーワードのプロパティなどがあり、紛らわしい場合は、このサンプル・ソースのように、Leftの代わりにMicrosoft.VisualBasic.Leftといった長い完全修飾名の記述が必要となる場合がある。長い完全修飾名は、クラス・ライブラリのリファレンスを引くことで知ることができる)。その結果、Null(Nothing)値を引数にとった場合のLeft関数の挙動に相違が生じているわけである。文字列関連関数で、文字列以外の値を扱うことはめったにないかもしれないが、意図しないバグにより、それを処理してしまっている可能性もある。もし、VB.NETでプログラミングしていて、文字列関連の挙動がVB 6と異なるときは、チェックしてみる価値があるだろう。
『VB6プログラマーのための入門 Visual Basic .NET 独習講座』
本記事は、(株)技術評論社が発行する書籍『VB6 プログラマーのための 入門 Visual Basic .NET 独習講座』から許可を得て転載したものです。
【本連載と書籍の関係について 】
この書籍は、本フォーラムで連載した「連載 プロフェッショナルVB.NETプログラミング」を大幅に加筆修正し、発行されたものです。技術評論社、および著者である川俣晶氏のご好意により、書籍の内容を本フォーラムの連載記事として掲載させていただけることになりました。
→技術評論社の解説ページ
ご注文はこちらから
|
業務アプリInsider 記事ランキング
本日
月間