t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA ジョージ・ブールとIf文とBoolean

VBAのBoolean型は、由来をたどれば数学者ジョージ・ブールの名前である。
ある意味、この方のおかけで今のIf文があるといっても過言ではない。

Googleのトップページで知ったのだが、今日はブールさんの生誕200周年らしい。

おめでとうございます。

以下Wikipediaより引用
f:id:t-hom:20151102055508p:plain

ジョージ・ブール(George Boole, 1815年11月2日 - 1864年12月8日)は、イギリスの数学者・哲学者。今日のコンピュータを理論的に支える記号論理学であるブール代数の提唱者として知られる。

さて、良い機会なのでVBAのBoolean型について書く。

ときどき次のように「If ○○ = True Then」というパターンを目にする。

Sub hoge()
    If ThisWorkbook.Saved = True Then
        MsgBox "このブックは保存されています。"
    Else
        MsgBox "このブックは保存されていません。"
    End If
End Sub

If文に必ず比較演算子を書かないといけないと思い込んでいる方もいるかもしれないが、If文が評価するのはあくまでBoolean型である。
「ThisWorkbook.Saved」はBoolean型を返すので、Trueと比較するまでもなく、以下のように直接記述すればよい。

Sub fuga()
    If ThisWorkbook.Saved Then
        MsgBox "このブックは保存されています。"
    Else
        MsgBox "このブックは保存されていません。"
    End If
End Sub

特にVBAにおいて上記のように書くメリットは、コードがそのままシンプルな文として読めることである。
「If(もし) ThisWorkbook(このブック).(が)Saved(保存されている) Then(ならば)」と読める。

Trueと比較してもまあ読めるけれど、「もしこのブックは保存されているが真ならば」というまどろっこしい表現になる。

さて、このようなテクニックを伝えたときに、初心者は「例外ルール」として理解するかもしれない。
恐らくプログラミング初心者は「If文には比較演算子を用いる」と理解している。
そこに「ただし、Boolean型の場合は比較する必要がない」と例外を付け加えることになる。
その理解は正確ではないので、ここで詳しく説明しておきたい。

正しくは、次の定義である。
「If文はBoolean型を評価する。」
「比較演算子はBoolean型を返す。」

あまり理解されていないのは、後者の「比較演算子」の定義である。

次のコードはBoolean型の変数bに対し、比較演算 3 > 1 の結果を代入し、If文ではそのbを判定に用いている。

Sub piyo()
    Dim b As Boolean
    b = 3 > 1
    If b Then
        MsgBox "正しい"
    End If
End Sub

もうひとつ別の例を挙げる。

Sub hogehoge()
    Dim b As Boolean
    b = 3 * 3 = 9
    If b Then
        MsgBox "正しい"
    End If
End Sub

VBAには演算子の優先順位がある。
まず算術演算の3*3が行われて9となり、次に9=9の比較演算がTrueを返し、Boolean型の変数bに代入される。
やはりIf文ではそのbを判定に用いている。

普通このような面倒なことはせず、If文に直接式を書くが、あくまでそれは比較演算子がBoolean値を返すという性質を利用したもので、If文イコール比較演算という理解は正確ではないということ。

また、以下のようにIf文でAndを用いて複数条件を判定するケースもある。

Sub fugafuga()
    a = 10
    b = 10
    c = 10
    If a = b And b = c Then
        MsgBox "aとcは等しい"
    End If
End Sub

「If文は、Andで複数の条件を指定できる」という理解は間違ってはいないが、これもAndやOrを例外ルールと見なす点でよろしくない。

Andは論理演算子の一種であり、以下のような定義が正確である。
「If文はあくまでもBoolean型を評価する。」
「論理演算子はBoolean型を返す。」

以下に具体的なコードで説明する。

Sub piyopiyo()
    a = 10
    b = 10
    c = 10
    Dim d As Boolean
    d = a = b And b = c
    If d Then
        MsgBox "aとcは等しい"
    End If
End Sub

比較演算と論理演算では比較演算の方が優先度が高いので、d = a = b And b = cという文は次のように理解できる。

 d = (a = b) And (b = c)

まず比較演算が行われ、d = True And True となる。
そして、論理演算の結果、d = Trueとなる。

If文が評価するのは、Boolean型である。
この事実に基づいたテクニックはよく使われるので、必ず覚えておきたい。

余談

最初に紹介したプログラムだが、IIf関数を用いて以下のように書くテクニックもある。

Sub hogehogehoge()
    MsgBox "このブックは保存されていま" & IIf(ThisWorkbook.Saved, "す。", "せん。")
End Sub

プログラマーは一般的に行数が増えるのを嫌う。
1つのプロシージャが画面の範囲を超えるとスクロールしないと見えなくなるので、コードの理解を妨げるからである。
特に1つの変数の使用範囲が1画面に収まらない場合は見通しが悪く、危険である。
IIfはIfとElseを1行で書けるので、覚えておくと何かと便利である。

ただし、If文と違って両方評価されるということに注意しておきたい。
どういうことか、実際のコードで説明する。

数値を0で割るとエラーが発生するが、次のコードはエラーにならない。

Sub fugafugafuga()
    If True Then
        MsgBox 1 / 1
    Else
        MsgBox 1 / 0
    End If
End Sub

IfにTrueが渡されており、Else部分は計算されないからだ。

しかし、次のコードはエラーになる。

Sub piyopiyopiyo()
    MsgBox IIf(True, 1 / 1, 1 / 0)
End Sub

IIfでは、TrueかFalseかに関わらず、いったん両方が計算されるため、False部分の1 / 0でエラーになる。
これを踏まえたうえで、If文とIIf関数を上手に使い分けすると良い。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。