87

I'm in the process of migrating a project from Visual Basic to C# and I've had to change how a for loop being used is declared.

In VB.NET the for loop is declared below:

Dim stringValue As String = "42"

For i As Integer = 1 To 10 - stringValue.Length
   stringValue = stringValue & " " & CStr(i)
   Console.WriteLine(stringValue)
Next

Which outputs:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

In C# the for loop is declared below:

string stringValue = "42";

for (int i = 1; i <= 10 - stringValue.Length; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

And the output:

42 1
42 1 2
42 1 2 3

This obviously isn't correct so I had to change the code ever so slightly and included an integer variable that would hold the length of the string.

Please see the code below:

string stringValue = "42";
int stringValueLength = stringValue.Length;

for (int i = 1; i <= 10 - stringValueLength; i ++)
{
   stringValue = stringValue + " " + i.ToString();
   Console.WriteLine(stringValue);
}

And the output:

42 1
42 1 2
42 1 2 3
42 1 2 3 4
42 1 2 3 4 5
42 1 2 3 4 5 6
42 1 2 3 4 5 6 7
42 1 2 3 4 5 6 7 8

Now my question resolves around how Visual Basic differs to C# in terms of Visual Basic using the stringValue.Length condition in the for loop even though each time the loop occurs the length of the string changes. Whereas in C# if I use the stringValue.Length in the for loop condition it changes the initial string value each time the loop occurs. Why is this?

slee423
  • 1,307
  • 2
  • 20
  • 34
  • 3
    It is interesting that many only conversion utilities convert this incorrectly. – Magnus Oct 02 '18 at 11:54
  • 8
    [Microsoft](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for) clearly outlines what your problem is... – Trevor Oct 02 '18 at 12:39
  • 39
    @Çöđěxěŕ: Stop, please. If robotically removing tags from the title without regard to context were helpful, the website would do it. – Ry- Oct 02 '18 at 13:43
  • 1
    So I assume this is not in part of editing new questions? Can you tell me when the consensus is to not remove tags from questions? I actually see many post being edited to exclude the tags as they are not helpful in setting the tone to the actual question when tags are used. I believe that is why the tagging system exist in order to show people the relevant subjects they are interested in? In the end is this a personal choice, he said she said? – Trevor Oct 02 '18 at 13:53
  • 11
    @Çöđěxěŕ You can find some info about that [here](https://meta.stackoverflow.com/questions/253028/why-is-removing-tags-from-the-title-suggested-so-often) – pushkin Oct 02 '18 at 16:45
  • @pushkin thanks for the link, but [meta](https://meta.stackexchange.com/a/130208) explains this well. So the question still stands unanswered, is this a personal choice/decision? If we have multiple places that say this and that, which one do we enforce and or follow? – Trevor Oct 02 '18 at 17:10
  • 35
    @Çöđěxěŕ I don't think that the two posts contradict each other. The point is: don't awkwardly stick a tag in the title like "question about this thing - tag". But if the title is a complete sentence that includes the tag, then it is *sometimes* ok. "Why does for loop behave differently when migrating" feels like a way too generic title. – pushkin Oct 02 '18 at 17:26
  • 5
    The important thing to remember is that these are two different languages. – user3629249 Oct 02 '18 at 20:45
  • 26
    @Çöđěxěŕ "migrating VB.NET code to C#" is clearly a full phrase that adds useful information to the title. Don't make edits that decrease clarity. Hopefully, that notion is common sense enough that we don't need a Meta post to back it up. – jpmc26 Oct 02 '18 at 23:55
  • 2
    Generally speaking, VB has much more in common with Fortran than with C-derived languages (although less so in .NET than in VBA and classic VB which share column-major array layout). C# `for` loops are virtually identical to C `for` loops. VB `For` loops are virtually identical to Fortran `DO` loops. – Craig Oct 03 '18 at 18:15
  • 1
    @Çöđěxěŕ "The only time you should use tags in your title is when they are organic to the conversational tone of the title."; "The title would be much more well-received if rewritten like this: Can I use jQuery to foo the bar on the baz, or am I stuck using plain JavaScript?" -- from your link. – user202729 Oct 04 '18 at 09:06

4 Answers4

115

In C#, the loop boundary condition is evaluated on each iteration. In VB.NET, it is only evaluated on entry to the loop.

So, in the C# version in the question, because the length of stringValue is being changed in the loop, the final loop variable value will be changed.

In VB.NET, the final condition is inclusive, so you would use <= instead of < in C#.

The end condition evaluation in C# has the corollary that even if it doesn't vary but it is expensive to calculate, then it should be calculated just once before the loop.

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
  • Thanks for the reply. I now realise that using `<=` allows me to iterate and have the same output as the VB code. However, I'm more interested in knowing as to why I've had to declare the integer variable and in `VB` I didn't have to. I'm going to update my question to show the same output. – slee423 Oct 02 '18 at 11:50
  • @slee423 The reason is given in the first sentence of my answer. Because the length of `stringValue` is being changed in the loop, the final loop variable value will be changed. – Andrew Morton Oct 02 '18 at 11:54
  • 1
    apologies, thanks for that answer. And thanks for elaborating it in more detail for me. – slee423 Oct 02 '18 at 11:55
  • 1
    @slee423 I added that into the answer as it does indeed clarify it. – Andrew Morton Oct 02 '18 at 11:59
22

Now my question resolves around how VB differs to C# in terms of VB using the stringValue.Length condition in the for loop even though each time the loop occurs the length of the string changes.

According to the VB.NET documentation:

If you change the value of counter while inside a loop, your code might be more difficult to read and debug. Changing the value of start, end, or step doesn't affect the iteration values that were determined when the loop was first entered.

So, the value of To 10 - stringValue.Length is evaluated once and reused until the loops exit.

However, look at c#'s for statement

If the for_condition is not present or if the evaluation yields true, control is transferred to the embedded statement. When and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), the expressions of the for_iterator, if any, are evaluated in sequence, and then another iteration is performed, starting with evaluation of the for_condition in the step above.

Which basically means that the condition ; i <= 10 - stringValueLength; is evaluated again each time.

So, as you saw, if you want to replicate the code, you need to declare the final counter in c# before starting the loop.

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
11

In order to make the example more understandable, I will convert both for loops into C# while loops.

VB.NET

string stringValue = "42";

int min = 1;
int max = 10 - stringValue.Length;
int i = min;
while (i <= max)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

C#

string stringValue = "42";

int i = 1;
while (i <= 10 - stringValue.Length)
{
    stringValue = stringValue + " " + stringValue.Length.ToString();
    Console.WriteLine(stringValue);
    i++;
}

The difference is then:

VB.NET caches the maximum value for i, but C# recomputes it every time.

camerondm9
  • 1,005
  • 15
  • 22
Maxime Recuerda
  • 476
  • 3
  • 14
7

Because the for in VB is a different semantic than the for in C# (or any other C-like language)

In VB, the for statement is specifically incrementing a counter from one value to another.

In C, C++, C#, etc., the for statement simply evaluates three expressions:

  • The first expression is customarily an initialization
  • The second expression is evaluated at the start of each iteration to determine whether the terminal condition has been met
  • The third expression is evaluated at the end of each iteration, which is customarily an incrementer.

In VB, you must supply a numeric variable which can be tested against a terminal value and incremented on each iteration

In C, C++, C#, etc., the three expressions are minimally constrained; the conditional expression must evaluate to a true/false (or integer zero/non-zero in C, C++). You don't need to perform an initialization at all, you can iterate any type over any range of values, iterate a pointer or reference over a complex structure, or not iterate anything at all.

So, in C#, etc., the condition expression must be fully evaluated on each iteration, but in VB, the terminal value of the iterator must be evaluated at the beginning, and need not be evaluated again.

C Robinson
  • 411
  • 4
  • 18