[VB.NET] Integer * String は何型になる?
VB.NET では遅延バインディングをする時を除き、必ず `Option Strict On` するべきです。そうしないと驚くべきことが起きます。もっと悪いことに、驚くべきことが起きていることに気づかないケースも起きます。
今回はそんな驚くべきことの一例をあげます。
Integer * String の結果はどうなる?
以下のコードは意図的に `Option Strict Off` にしています。
Option Explicit On
Option Strict Off
Option Infer On
Module Program
Sub Main()
Dim i As Integer = 1
Dim s As String = Console.ReadLine()
Dim answer1 = i * s
Console.WriteLine(answer1.GetType())
Dim answer2 = s * i
Console.WriteLine(answer2.GetType())
End Sub
End Module
この例では Infer On なので、answer1, answer2 は Object 型ではなく、ちゃんと推論され型付けされます。ここでの問題はそれが何型になるかです。(Infer Off では Object 型になりますが、本当の型は GetType() メソッドの呼び出して表示されるので確認できます。)
Integer 型?String 型?
ChatGPT 4o mini 上で試したところ 4 回も間違え、5回目でようやく正解しました。まあ、ネット上にほぼほぼ無い情報なので ChatGPT は学習できないのでしょう。たぶん。
正解は
Double 型です。予想できましたか?
なぜそうなるのか
まず、String は掛け算をする前に Double に変換されます。
次に、基本的な二項演算子は両辺の型をそろえたうえで適用されます。今回の operator * は Double で型が揃えられます。そのため Operator * の呼び出し時に、Integer の方も Double に変換されてしまうことに注意してください。
Class Double
Shared Operator *(left As Double, right As Double) As Double
Return left * right
End Operator
End Class
このようなメソッドを呼ぶイメージで、Operator * の計算結果もまた Double であるということになります。
仮に結果で Integer を期待するならば Double から Integer への縮小変換も必要になります。
' 型変換の位置を間違えている
' 一見正しく動作するので、おそらく間違いに気づかない
Dim answer1 = CInt(i * s)
Dim answer2 As Integer = s * i
読み手に苦痛を与え、動作も無駄が多く遅いコードです。
`Option Strict On` にしよう!
今回の例で `Option Strict On` にしていれば、暗黙の型変換を許可しないのでちゃんとコンパイルエラーになります。そして、「String から Double への変換」をしようとしていると教えてくれます。文字列は Double ではなく、Integer として扱わなければならないと気づくことができ、文字列に対して適切にキャストを書くこともできます。
Dim i As Integer = 1
Dim s As String = Console.ReadLine()
Dim answer1 = i * CInt(s)
Console.WriteLine(answer1.GetType())
Dim answer2 = CInt(s) * i
Console.WriteLine(answer2.GetType())
Integer * Integer が Integer になるという、非常に分かりやすく、動作も早いコードになりました。
コンパイラを味方につけましょう。型を意識しましょう。