ブログ「サイバー少年」

ブログ「サイバー少年」へようこそ!
小学六年生ごろからプログラミングを趣味にしている高校生のブログです。
勉強したことについての記事などを書いています。フリーソフトも制作、公開しています。
(当ブログについて詳しくは「ブログ概要紹介」を参照)

サイバー少年が作ったフリーソフトは「サイバー少年の作品展示場」へ

VB.NETの配列のSystem.Array的な仕組み

VB.NETには、今までのVBの文法に限りなく近くしつつ、
.NET Frameworkの仕様に合わせようとする努力が見られます。

今回、注目するのは配列です。

VB.NETの配列はC#と同じく、しっかりSystem.Arrayを継承したものを型にしているわけで、

Dim ints() As Integer

なんてありえない宣言なのです。

本来なら

Dim ints As Integer()

とするべきです。


…実はこういう宣言も可能で、こちらはC#の概念に近いやり方です。

Integer() は配列の型を表します。

そのため Integer(2) のような要素数を指定する書き方はできません。

C#で int[2] ints; と書けないのと同じことですね。

(Dim ints(2) As Integerと書けばOKな理由は、ints(2)が型を表していないからです。詳しくは後述します。)


さて、それでまぁ、内部的には後者のような仕組みになっているはずです。


そこで、VB.NETでの色々な配列宣言がC#ではどうなるのかという書き方の対応を考えてみました。

C#は文法に一貫性を持たせることを重視しているようで、配列もArrayクラスそのまんまの宣言方法になるのです。

それなら“[]”みたいな記号は表れないって?

つまり、C#での書き方をみるということは、.NETの内部的な解釈方法をみるということです。

これで、VB.NETの正体が分かりますね。


さて、実はこの対応リストは私の推測です。

「たぶんこうなっているだろうな~」、と考えて書いています。

大丈夫だろうとは思いますが、間違いがあればご了承ください。




1. 空の配列

VB.NET: Dim ints() As Integer
C#: int[] ints;

C#のほうのコードを見ればよく分かるように、変数はNothing(null)です。
もちろんNothingの配列を使うわけではなく、後述する“宣言と同時に初期化”の方法を取ることが多いです。


2. 宣言と同時に初期化

VB.NET: Dim ints() As Integer = {0, 1, 2}
C#: int[] ints = {0, 1, 2}

要素数3の配列のインスタンスを代入しています。
両方とも型推論していますね。


3. 要素数を指定して宣言

VB.NET: Dim ints(2) As Integer
C#: int[] ints = new int[3];

これはなかなか面白いですね。

“要素数を指定して宣言”なんて概念はC#にはありません。
C#ではあくまでも、int配列型の変数を宣言→要素数3のインスタンスを代入となっています。

VB.NETでも内部的にはそうなっていると思いますが、恐らく旧VBとの互換性のために、
概念上はC言語のような固定された配列になっているのです。(静的配列と呼ばれています)

しかし、内部的には{0, 0, 0}と初期化しています。(任意の値での初期化も可能)

また、C#では要素数を書くのに対して、VB.NETでは添字の最大値(要素数 - 1)を指定します。

VB.NETのDim ints(2) As Integerは要素数3になりますね。
これも恐らく旧VBがそうだったのではないでしょうか。


4. 直接インスタンス

VB.NET: New Integer() {0, 1, 2}
C#: new int[] {0, 1, 2}


VB.NETでもこんな書き方ができるわけです。
できないと話にならない部分も多いですからね。

コードの構造は全くC#と同じです。

ただ、VB.NETの場合、配列のカッコとコンストラクタのカッコが同じ記号ですから、ややこしいですね。

これはコンストラクタではなく、“Integerの配列を表す型”として認識されます。

また、両方ともカッコの中に要素数を指定できます。
ただ、さっきと同じように、VB.NETでは(要素数 - 1)で指定します。


5. 型推論について

VB.NET: {0, 1, 2}
C#: {0, 1, 2}

両方とも、配列のインスタンスを直接、書いたときに型推論させることが可能です。

ここに書いた例だと型が特定できませんが、文脈でIntegerとかShortとか判断します。

ただ、型推論はVB.NETのほうが優れている感じがしますね。

C#では変数の初期化時しか配列の型推論はできませんが、VB.NETは代入先の型を見て推論してくれます。

まぁ、C#は型を曖昧にしないために、あえて推論を不可にしているのだと思います。


6. ReDim

VB.NET: ReDim ints(3)
C#: ints = new int[4];

VB.NETでは複雑にReDimと名乗っていますが、結局は新しい配列のインスタンスを代入しているだけです。

しかし、VB.NETでは「インスタンス」という言葉はなるべく使いたくないみたいで、ReDimになっています。(それと互換性)

また、VB.NETのReDim Preserveは、C#では今までの配列の中身をコピーした新しい配列のインスタンスとなります。




ではでは、冒頭で触れた、なぜ

Dim ints(2) As IntegerがOKで、
Dim ints As Integer(2)がダメなのか

を説明します。


VB.NETの変数宣言は
Dim 変数名 As 型名
と書きますから、

本来は Dim ints(2)… と、変数名のあとに配列という“型”を表すものをつけるのは駄目なわけです。

C#ではそれが厳守され、 int[] ints となっています。
(「型名 変数名」の書式)


しかし、VB.NETでは、変数名のあとに“型”を指定することが許可されています。

これは互換性のためもあるでしょうが、それだけではありません。

先ほども書きましたが、
Dim ints As Integer() = New Integer(2)
(Integerの配列の型の変数にIntegerの配列のインスタンスを代入)
というコードの省略形とみなすことができます。


さらには、これは省略の意味だけでなく、インスタンスの存在を隠蔽する意味も含まれています。

VB.NETは、なるべく旧VBに近い文法にしたいため、.NET Frameworkの原則(インスタンスの存在)だって隠すのです。


しかし、なぜ
Dim ints As Integer(2) が駄目なのでしょうか。

これをOKにするのは、さすがに隠蔽しすぎ、と考えたのではないかと思います。

繰り返し言いますが、
この要素数を指定する“(2)”は、型ではないのです。

Integer()型はIntegerの配列を表す単なる型です。

要素数はインスタンスが決めるのです。

C#の配列のコードをみると、要素数はインスタンスが決めているということがよく分かります。


つまり、あくまでも型は数字が無いInteger()なわけで、
さすがに Dim 変数名 As 型名 の、
“型名”を意味する場所にインスタンスを指定するようなものを入れる、
というコードを許可するのはやりすぎではないかと思ったのではないでしょうか。


しかし、さっきの変数名のあとに書くやり方は、しょせん省略形なのでOKと思ったのではないでしょうか。

というわけで、あまり.NETのシステムを無視して突っ走るのもいけないんですね。




VB.NETは旧VBとC#の狭間で苦しんでいるようですね…。

やはり、互換性を保ちながらの新技術対応は無理があるんじゃないでしょうかね。


それにしても長文になってしまった。

詳しく書きましたからね~。

tag:

コメント

コメントの投稿

トラックバック

トラックバック URL
http://cyberboy6.blog.fc2.com/tb.php/276-66609526
この記事にトラックバックする(FC2ブログユーザー)

当ブログをご利用(閲覧等)になる場合は必ず「当ブログの利用規定」をお守りください。