scottyeatscode
scottyeatscode

Reputation: 606

VB vs C#: Why is this possible?

Here is some code that troubles me every time I think about it.

Option Strict On

Module Module1

    Sub Main()
        For Each i As Integer In New String() {"why", "is", "this", "tolerated?"}
            ' compiles just fine.
        Next
    End Sub

End Module

C# simply will not allow converting strings to integers implicitly.

class Program {
    static void Main(string[] args) {
        foreach (int i in new string[] {"that's", "better"}) {
            // will not compile, and for good reason.
        }
    }
}

Why does VB let us do that? I'm trying to have fun with this because I'm still relatively new here, but I'm also genuinely curious. I'm sure there are devs out there with the answer.

Upvotes: 22

Views: 696

Answers (4)

As a supplement to Mark's answer, here's how the compiled vb.net code looks like. As you can see the code is compiled to a For...Next statement and the error occurs only at run-time when trying to convert the string to integer.

Dim VB$t_array$L0 As String() = New String() { "why", "is", "this", "tolerated?" }
Dim VB$t_i4$L0 As Integer
For VB$t_i4$L0 = 0 To VB$t_array$L0.Length - 1
    Dim i As Integer = Conversions.ToInteger(VB$t_array$L0(VB$t_i4$L0))
Next VB$t_i4$L0

Upvotes: 6

Amorphis
Amorphis

Reputation: 398

Am I the only one that can see that in the VB code the array is a generic(variant) array while the C# code contains strict string array ?

Upvotes: 0

Hans Passant
Hans Passant

Reputation: 941495

Microsoft apologizes for this in the Language Specification, chapter 10.9:

The current element of the iteration is converted to the type of the loop control variable even if the conversion is explicit because there is no convenient place to introduce a conversion operator in the statement. This became particularly troublesome when working with the most common collection type, System.Collections.ArrayList, because its element type is Object. This would have required casts in a great many loops, something we felt was not ideal.

Ironically, generics enabled the creation of a strongly-typed collection, System.Collections.Generic.List(Of T), which might have made us rethink this design point, but for compatibility’s sake, this cannot be changed now.

Upvotes: 11

Mark Hall
Mark Hall

Reputation: 54532

It appears to be a idiosyncrasy of the For Each Statement. According to the documentation it is evaluated at Runtime.

From Link:

When Option Strict is set to On, narrowing conversions ordinarily cause compiler errors. In a For Each statement, however, conversions from the elements in group to element are evaluated and performed at run time, and compiler errors caused by narrowing conversions are suppressed.

In the following example, the assignment of m as the initial value for n doesn't compile when Option Strict is on because the conversion of a Long to an Integer is a narrowing conversion. In the For Each statement, however, no compiler error is reported, even though the assignment to number requires the same conversion from Long to Integer. In the For Each statement that contains a large number, a run-time error occurs when ToInteger is applied to the large number.

Upvotes: 14

Related Questions