公式ドキュメントが読まれない こんな世の中じゃ ポイズン

# まえがき
むかーし、グーグルで適当な個人サイト探すより、なるべく公式ドキュメントを参照してねという動画を作ったことがあります。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ExcelVBA　一口講座 資料の調べ方 <a href="https://t.co/loD36SEETu">https://t.co/loD36SEETu</a> <a href="https://twitter.com/hashtag/sm21809660?src=hash&amp;ref_src=twsrc%5Etfw">#sm21809660</a> <a href="https://twitter.com/hashtag/%E3%83%8B%E3%82%B3%E3%83%8B%E3%82%B3%E5%8B%95%E7%94%BB?src=hash&amp;ref_src=twsrc%5Etfw">#ニコニコ動画</a></p>&mdash; m.ita (@mima_ita) <a href="https://twitter.com/mima_ita/status/1152339345652629504?ref_src=twsrc%5Etfw">2019年7月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

残念ながら、「動けばいいんだよ」勢には効果がなかったようなので、最近、見つけた一見動くが、公式ドキュメントで認められていないことやってバグが出る例を出してリベンジしようと思います。

# 問題
Excel VBAで動的配列の作成されているか否かを判断するにはどうしたらいいでしょうか？
たとえば以下のコードでエラーになる場合と、ならない場合を判別する方法を考えてみてください。

```vb
Public Sub test()
     Dim v() As Variant
     ' Debug.Print UBound(v) ' エラーになる
     
     ReDim v(1) As Variant
     Debug.Print UBound(v)
     
     Erase v
     ' Debug.Print UBound(v) ' エラーになる
End Sub
```


# 想定される回答
おそらく、googleとかで検索した場合に、この問題で想定される回答は次の４つになります。

##OnErrorを使用する方法
動的配列が作成されていなかったり、削除されている場合でUBoundやLBoundでエラーが発生するなら、素直にエラーハンドリングをして動的配列の作成の有無をチェックします。

```vb
Public Sub testArraySample()
    Dim v() As Variant
    Debug.Assert isEmptyArray(v) = True
    
    ReDim v(1) As Variant
    Debug.Assert isEmptyArray(v) = False
    
    Erase v
    Debug.Assert isEmptyArray(v) = True
End Sub

Private Function isEmptyArray(v() As Variant) As Boolean
On Error GoTo ErrUbound:
    Dim tmp As Long
    tmp = UBound(v)
    isEmptyArray = False
    Exit Function
ErrUbound:
    If Err.Number <> 9 Then
        Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    End If
    isEmptyArray = True
End Function
```

##SafeArrayGetDimを利用する方法
VBAの配列は動的であれ、固定であれ、SafeArrayになっています。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms221482%28v=vs.85%29.aspx

このSafeArrayの次元数はSafeArrayGetDimで取得できます。次元数が０ならまだ配列が作られていないと判断できます。
http://msdn.microsoft.com/en-us/library/windows/desktop/ms221539%28v=vs.85%29.aspx


```vb
Private Declare PtrSafe Function SafeArrayGetDim Lib "oleaut32" (ByRef psa() As Any) As Long

Private Function isEmptyArray(v() As Variant) As Boolean
    If SafeArrayGetDim(v) <> 0 Then
        isEmptyArray = False
    Else
        isEmptyArray = True
    End If
End Function
```

##Sgnを使う方法
Sgnを利用することで判定できます。
なんで動くかはよくわかりません（ﾄﾞﾔｧ！)

```vb
Private Function isEmptyArray(v() As Variant) As Boolean
    If Sgn(v) Then
        isEmptyArray = False
    Else
        isEmptyArray = True
    End If
End Function
```


## Not Notを利用する場合
Not Notのテクニックを使うことで判定できます。
なんで動くかはよくわかりません（ﾄﾞﾔｧ！)

```vb
Private Function isEmptyArray(v() As Variant) As Boolean
    If Not Not v Then
        isEmptyArray = False
    Else
        isEmptyArray = True
    End If
End Function
```

# 各実装の評価
まず、簡単な動作確認だと、この４つのソースコードは、それっぽく動作します。
その上で、レビューで、このコードに遭遇した場合どう判断するか考えてみてください。

仮に私がレビュワーだった場合は以下のような判定をします。

##OnErrorを使用する方法
VBAの言語仕様通りの実装なのでレビューを通します。

##SafeArrayGetDimを利用する方法
WinAPIを使っているので32bitと64bitの両方のExcelで動くか微妙な宣言ですが、少なくともMSDNの根拠があるので**32bit/64bit両方のExcelで動作確認しておくこと**という条件でレビューを通します。

また、レビュー時に、SafeArrayのあたりの根拠の説明ができない場合は、仮に動くコードでも却下します。


##Sgnを使う方法
これは却下します。
この実装の動かないケースについては以下のページに詳しく書いてあります。

**VBAで配列のNull判定にSgn関数を使ってはいけない**
https://qiita.com/satoko138/items/7e06dda56683065968f7

簡単にいうと、配列の割り当て前はアドレスが0になる。
IF分岐でそのままだと判定できないので、Sgn関数を通してからIF分岐に渡している。

しかし、[Sgn関数の仕様](https://docs.microsoft.com/en-us/openspecs/microsoft_general_purpose_programming_languages/ms-vbal/b7bbdcd3-c8fc-4f42-b362-18ace8f2be55)として引数には「Double containing any valid numeric expression.」とあるので、配列などを渡すと、一見動く場合もあるが、予期せぬ動作をしてしまう。


## Not Notを使う方法
これも却下です。
Sgn関数の代わりにNot論理演算子をつかって回避していますが、[VBAの論理演算子](https://docs.microsoft.com/en-us/openspecs/microsoft_general_purpose_programming_languages/ms-vbal/2d70780d-6e99-47d6-9759-2b3a46b8e862
)の説明に「§ A logical operator is invalid if the declared type of any operand is an array or a UDT.」、つまり論理演算子に配列渡しても無効と明記してあります。

「Sgnを使う方法」とことなり、予期せぬ結果になるパターンを見つけられていませんが、「見つからない＝不具合がない」ということではないので、先の公式ページより信憑性の高い資料を提出しない限り却下です。

# いいたいこと
・とりあえず公式のページを参考に論理をたてられるようにしましょう
　→**Qiita含めて個人サイト**より優先的に参考にしましょう。

・もし、公式のページが読みづらくて、個人サイトとかを参考にするとしても、その個人サイトが公式を参考にしているかで信憑性を判断しましょう。

・動けばいいってのはだめです。
　→テストの原則で「欠陥がない」ことは示せないから、よくわからんけど動いたなんてのはレビューで通せるわけないです。

・とりあえず公式ページ参照していれば、結果が間違っても責任回避できます。

（補足）
・Googleで調べて何故か公式より信憑性のないサイトが上にくる場合はGoogleの設定を英語設定にするとマシになるかもしれません
　https://qiita.com/mima_ita/items/29e02c755062921e5e87