連載:[完全版]究極のC#プログラミング

Chapter12 varによる変数宣言とコレクション初期化子

川俣 晶
2010/02/01

12.2 Variant型の悪夢

 C# 3.0の「暗黙的に型指定されるローカル変数」をわかりやすく説明するために、それとは明らかに違うVBのVariant型を紹介し、相違点を示すことにする。違うものと対比するほうが、特徴がわかりやすく浮かんでくるからである。

 VBのVariant型とは、VB 2.0から6.0までに存在するデータ型で、どのような型の値でも格納できる“魔法の箱”として機能する。変数宣言時に型を省略した場合はこの型になるので、型をいっさい明示せずにソースコードを記述することも不可能ではない(明示的な型変換を行うコードを含む可能性はあるが)。Variant型を、(6.0までの)VBらしさを象徴する特徴的な機能と思う技術者も多いのではないかと思う。特に、日本ではVB 1.0日本語版がリリースされておらず、Variant型導入前のVBを知らない技術者が大多数と思われるため、その傾向は顕著だろう。

 しかしながら、筆者はVB 1.0時代からVBを使い込んでいたので、違う印象を持っている。VBに詳しければ詳しいほど意外に思われる可能性があるが、実は、VB 1.0は、厳格に型付けされた言語であった。何でも入る“魔法の箱”は存在せず、変数を宣言する際に型を省略すると整数(Integer)型と見なされ、整数は代入できても文字列は代入できない変数だったのである。

 型はソースコード上で明示するほうがよい、と思っていたので、筆者はこのようなVBの仕様を素直に受け止め、変更される可能性などまったく考えていなかった。しかし、VB 2.0になったとき、あらゆる機能が好ましい意味で“改良”されていたにもかかわらず、Variant型が導入されて型を明示しないプログラミングが可能になったことに驚いた。その当時、これは悪夢そのものであり、Variant型は使うべきではない、と筆者は考えた。VB 2.0唯一の決定的な弱点と思ったのである。

 ちなみに、何でも入る魔法の型といえば、C#ではobject型がそれに当たる。しかし、object型とVariant型は同じではない。object型は参照型であり、値型の値を扱うにはボックス化という手順が必要になる。また、参照型である以上、メモリの確保と破棄というオーバーヘッドが必ず付いて回る。しかし、Variant型は整数のような値であっても、オブジェクトへの参照であっても、それをそのまま格納できる。ボックス化やメモリの確保、解放のオーバーヘッドもない。まさに万能の魔法の箱である。

 では、Variant型の何が問題なのだろうか? Variant型の悪夢の典型的な例を1つ挙げよう(リスト12.1参照)。コメントを多く補ったので、VBの文法は知らなくても読めるだろう。

Private Sub Form_Load()

  Dim a, b           ' 変数aとbを宣言(Variant型)

  a = 1              ' 整数の1を代入
  b = "2"            ' 文字列の「2」を代入
  Debug.Print a + b  ' aとbを加算して出力

  a = "1"            ' 文字列の「1」を代入
  b = 2              ' 整数の2を代入
  Debug.Print a + b  ' aとbを加算して出力

  a = "1"            ' 文字列の「1」を代入
  b = "2"            ' 文字列の「2」を代入
  Debug.Print a + b  ' aとbを加算して出力

End Sub
リスト12.1 Variant型の悪夢の例(VB 6.0で記述し、動作確認した)

 3
 3
12
リスト12.1の実行結果

 最初の2つの加算では、整数と文字列を整数化した値を加算して結果としている。そこで、同様の結果を期待して文字列と文字列を加算させると期待は裏切られて、「整数の足し算」ではなく「文字列連結」が行われてしまう。

 このような結果になる理由は、Variant型ではなく+演算子が持つ機能にある。ここで、Variant型が悪夢を持ち込むのは、原因と結果の因果関係を切り離す効能を持つためである。もし、"1" + "2"という式を直接書けば、結果が3ではなく"12"になることは誰でも容易に予測できるだろう。しかし、Variant型変数が介在することで、原因と結果の因果関係が見えにくくなり、すぐ原因が推定できない深刻なバグを作り込んでしまうリスクを持つ。

 このような問題を解決する最も簡単なやり方は、型を明示することである。変数の宣言を次のように書き換え、整数を示す型名であるIntegerを明示的に指定する。

Dim a As Integer, b As Integer

 これで実行結果は次のようになり、意図どおりとなる。

 3
 3
 3
リスト12.1で変数a、bをInteger型にした場合の実行結果

 最初にC# 3.0の「暗黙的に型指定されるローカル変数」を見たときに感じたのは、上記のような「Variant型の悪夢」の再来であった。しかし、それはまったくの誤解であった。はたして、どのような誤解だったのだろうか?


 INDEX
  [完全版]究極のC#プログラミング
  Chapter12 varによる変数宣言とコレクション初期化子
    1.12.1 暗黙的に型指定されるローカル変数
  2.12.2 Variant型の悪夢
    3.12.3 暗黙的に型を明示する
    4.12.4 なぜvarを使うのか?
    5.12.5 varが使用できない場面
    6.12.6 varを活用できる場面
    7.12.7 暗黙的に型指定されるローカル配列
    8.12.8 暗黙に型付けされた配列と型の推測
    9.12.9 暗黙に型付けされた配列とnull
    10.12.10 コレクション初期化子
    11.12.11 Dictionaryクラスとコレクション初期化子
    12.12.12 引数が2つのAddメソッドとコレクション初期化子/C#olumn
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間