What should this code do?

OK, I’ve got a question for y’all. Take a look at the code sample at the end of this entry and leave me a comment on what you think the output of the program should be. Note that I’m looking for people’s opinions here and this isn’t one of those “how well do you know VB” trick questions. Once you’ve put in a comment on what you think the output should be, then feel free to run it and see what it does, but do hold off commenting on the actual behavior until people have had a chance to comment. Once we’ve got some comments, I’ll write a longer entry on why I’m asking this and why the answer matters at this particular moment in time.

Module Module1

    Sub Main()

        For i As Integer = 0 To 2

            Dim x As Integer

            Console.WriteLine(x)

            x += 1

        Next

        Console.ReadLine()

    End Sub

End Module

93 thoughts on “What should this code do?

  1. Anonymous

    Vote 2 for

    0

    0

    0

    Also wouldn’t mind a compiler warning on the x += 1 being useless, thought that may be too hard to detect.

    Reply
  2. Tim Hall

    I would have to disagree with the last 2. I say the output would be.

    0

    1

    2

    I believe this is because we never leave the scope of the for block, hence the X variable stays in scope and the value is not lost.

    I have used that (correctly or incorrectly) a few times as i only needed the variable inside the loop and it makes sense to limit the scope of the variables to what you need.

    Reply
  3. Brian Schmitt

    0

    1

    2

    I also agree with Tim… It is declared inside the loop and therefore never loses scope.

    I also agree with Anon. that maybe a warning that declared variables INSIDE a loop may retain previous held values… However, most material (books) that I have read in the past has warned of this anyways.

    Reply
  4. Greg

    I’m in the:

    0

    1

    2

    camp. Variable x is initialised "by default" to 0 (though not explicitly) and is incremented 3 times, but is not displayed after the final increment.

    In C# the equivalent of this would give a compiler error, as x had not been initialised when it is incremented:

    namespace ConsoleApplication1

    {

    class Program

    {

    static void Main(string[] args)

    {

    for (int i = 0; i <= 2; i++)

    {

    int x;

    x += 1; // <— compile error here: "Use of unassigned local variable ‘x’"

    Console.WriteLine(x);

    }

    Console.ReadLine();

    }

    }

    }

    This may be nothing to do with what you’re getting at, but although I program in VB pretty much exclusively, I’m not a fan of the ‘default initialising’ behavior, and prefer the C# approach.

    Reply
  5. Dave Rothgery

    It _should_ cause the compiler to output "are you sure you really want to do this?", because declaring a variable of a value type inside of a loop doesn’t make much sense. What it actually does, though… I’d bet on 0,0,0 but wouldn’t put money on it.

    Reply
  6. Ken Schultz

    I think the results will be 0 1 2. The default value of an integer = 0 which is the starting value then adds one each time

    Reply
  7. Mark Pearce

    What I want it to do:

    Compiler error or warning saying "Variable used without any value being assigned", similar to the C# message.

    What I would expect at first glance:

    0

    0

    0

    Reply
  8. David Golding

    I think it should be 000.

    The 012 camp seem to be ignoring the execution of the declaration which happens with each loop. Indentation hints that the three lines inside the for loop are not in the same scope as the loop.

    (And default initialisation makes sense to me.)

    Reply
  9. Phil Weber

    David: Prior to VB.NET, Dim statements were not executable, which is probably why people expect X to retain its value.

    Now, if the Dim statement said, "Dim X As Integer = 0", then I might expect X to be reinitialized each time through the loop.

    Reply
  10. Tim Hall

    Phil: I think that even in VB.Net Dims are not executable.

    I would expect the JITer to basically allocate memory for all the variables declared within a new scope at the same time (ie upon entering the scope).

    It would not make sense to reallocate memory for the same thing over an over again, if it had an initialiser i would expect the initializer to be executed each time and if the initializer was 0 then i would expect the output to be 0,0,0.

    My expectation of equivilency is

    Dim x as integer

    For i As Integer = 0 To 2

    Console.WriteLine(x)

    x += 1

    Next

    Console.ReadLine()

    with an initializer i would say it would be the equivalent of

    Dim x as integer = <initializer value>

    For i As Integer = 0 To 2

    x= <initializer value>

    Console.WriteLine(x)

    x += 1

    Next

    Console.ReadLine()

    But of course x would not be available outside the scope of the for loop.

    I could go as far as saying that X is declared in the same scope as i is.

    Reply
  11. Eric

    0

    0

    0

    The variable is defined inside the loop; on every pass through the loop, the variable should pass out of scope and be redefined.

    Consider the slight refactoring:

    For i As Integer = 0 To 2

    DoStuff

    Next

    Private Shared Sub DoStuff()

    Dim x As Integer

    Console.WriteLine(x)

    x += 1

    End Sub

    It’s clear that in this version, x should be reinitialized each time through; this code should be functionally (heh) equivalent to the OP.

    Reply
  12. RichB

    The output from vbc contains the following IL:

    IL_000e: add.ovf

    IL_000f: stloc.0

    IL_0010: ldloc.0

    which increments the for counter. I was under the impression that the dup instruction was better than a store/load sequence – as C# uses this.

    What gives?

    Reply
  13. Michele Bernardi

    I think the best should be:

    012

    If the code contains explicit initializer like this:

    Dim x As Integer = 0

    I would expect that it output 000

    This way will give an extra opportunity.

    Maybe the solution most easy to understand would be to just print 000.

    Reply
  14. Joe Brinkman

    I think the answer doesn’t matter. The fact that different people come up with two different answers for a trivial coding exercise, in and of itself speaks volumes about the problem. As I read through Abrams and Cwalina’s book on designing frameworks, it strikes me that this example suffers from the same problem that the guidelines are designed to prevent from happening. While this is clearly a language/compiler issue, I think the principles involved here are the same.

    Reply
  15. Alfred Thompson

    I’m tempted to say that it should do what ever the language specification says it should do but I suspect that "what should the specification say it should do" is what you are actually asking.

    I’ve gone back and forth with the question. Do I want the compiler to be "smart" and know that it only has to create and initialize the variable once? Do I want the compiler to be literal and initilize the variable each time through the loop? Or do I want the compiler to be brain dead and give me an error?

    Having this much ambiguity in code seems like a bad idea in any case. Beginners are going to get especially confused. Maybe what I want most is that a warning is given that tells people what is going to happen here.

    Reply
  16. Pingback: Computer Science Teacher

  17. Shoddy Coder

    I would expect this to return 0, 0, 0. I agree with a few people above:

    1. If we apply ExtractMethod refactoring we’d not expect any different behavior.

    2. I like the fact that C# gives an error and hate the fact that VB doesn’t even provide a warning.

    3. I like that C# requires you to specify the default values; however since VB was designed in such a way that it would default then in for you, it should work consistently and reinitialize that variable everytime like it would if were declared dim x as integer = 0

    Reply
  18. Sergio Pereira

    The output of the compiler should be a warning regarding the uninitialized variable, but the output of the program should definitely be:

    0

    0

    0

    Anything other than that would be unexpected and probably caused by some subtle detail (are there any other kinds of those?), which would contribute to buggy code, IMHO. The language should cause the code to do what it looks like it’s trying to do, as much as possible.

    Reply
  19. Matt

    I agree with 0,0,0

    Code can be written in many different ways, and should always work as intended. Eric points out a very reasonable refactor that I would not expect to alter the results. And why is C# smart enough to give an error when VB doesn’t even give a warning?

    Reply
  20. Bruce Johnson

    I’m in the 0,0,0 camp, for the reason that Shoddy Coder put forward. I hate the idea that performing an extract method on the body might introduce a bug to the code.

    In my idea world, the compiler should throw a warning saying something to the effect that incrementing x isn’t going to have any impact. This almost falls into the category of the compiler determining the coder’s intention. Which is the point of Sergio’s comment that the language should cause the code to do what it looks like it’s trying to do. The question is who’s to agree on what the code is trying to do. To me, it looks like it’s trying to output 0, 1, 2. Just failing badly πŸ˜‰

    Reply
  21. michael

    I seem to remember this being a special case in which the var declaration happens only the first iteration. This leads me to believe…012.

    While I think 000 is what <i>should</i> happen, I expect there are performance reasons why it might not.

    Reply
  22. Sergio Pereira

    I can’t agree with 0, 1, 2 … if the intent of the code was that, then th Dim would have been outside the For/Next block. We should not need to remember special rules, or trip-wires… I think the intent is clear: 0 0 0, even in C# if I ignore the compiler warning.

    Reply
  23. JustinM

    The problem is whether each iteration of the loop should create new variable. What it’s initialized to is irrelevant, and I suspect Paul now wishes he’d specifically initialized it to keep the discussion on topic.

    I think that whatever VB does now is what it should continue to do in the future.

    However, I hope that it prints zeros, because otherwise I don’t see a convenient way to get this behavior. If I want to create a new variable within each loop iteration then how am I going to do it unless it’s automatic? If I don’t want the variable created each iteration, then I can simply move it to the containing scope.

    Btw, I hope VB never warns about default initialization, or at least allows me to disable the warning. Rather than add this feature, it would be nicer to have the IDE automatically add the explicit initialization if that’s what the user chooses.

    Reply
  24. Bruce Johnson

    Sergio,

    The intention isn’t completely clear. The fact that x is incremented at the bottom of the loop and then never used is the complicating factor. Either the Dim at the top or the increment at the bottom is misplaced. So it’s not obvious (at least to me) whether the coder wants a new x with each iteration or not.

    Reply
  25. Sergio Pereira

    Bruce (sorry for transforming this into a message board),

    So, if I re-wrote the loop like:

    For i As Integer = 0 To 2

    Dim x As Integer

    Console.Write(x)

    x += 1

    Console.Write(x)

    Console.WriteLine(",")

    Next

    Do you still think it should print: "01,12,23" instead of "01,01,01" ? The increment at the bottom is just decorative in the orginal example IMHO.

    Reply
  26. Scott Swigart

    0

    1

    2

    X shouldn’t get reinitialized every time, unless an initialization value is specified, as in:

    Dim X as Integer = 0

    This would give you the flexibility to declare loop vars that don’t re-init every time through the loop, or declare loop vars that do re-init. Otherwise, X would need to be declared outside of the loop even though it’s only used inside of the loop.

    Reply
  27. karl

    I’d expect 0,0,0

    On one side i think the benefits of comforming with other general purpose languages in mass-use (c,++, #, java) has tremendous advantages. You’re compiler works the way a majority of developers expect it to.

    On the other side, I think VB.NET has different priorities and pressures than those other languages. The team works incredibly hard to make VB.NET more natural than any other. If, in their expert opinions, they think that the 0,1,2 behaviour is more natural and as such fits in with that VB.NET priority, so be it.

    I don’t think 0,1,2 is at all more intuiative or natural. I think it’s incredibly subtle. Maybe that’s the C bias talking though

    Reply
  28. Eric

    FYI, for those who haven’t run it, the code *does* print out 012, not 000. My refactoring prints out 000 on the other hand, which I think is a huge disconnect–it means that in at least in some cases in VB, an Extract Method refactoring may *not* be guaranteed safe, where the identical code and refactoring in C# *is* guaranteed not to change behavior.

    However, if you do initialize the variable at declaration (i.e. Dim x as Integer = 0) it will print out 000.

    I think the inconsistency is bad, myself, but it may be the only way to get a persistent-across-loops variable that’s scope-limited to the loop body, for whatever that’s worth.

    Reply
  29. Daniel Moth

    Some comments here seem to imply that if it was explicitly initialised there would be no difference. I beg to differ:

    http://www.danielmoth.com/Blog/2005/05/explicit-assignment-slower.html

    As to what the code should do it depends on your upbringing. Either way, if refactoring doesn’t preserve the functionality, then it is a bug with Refactoring and not the compiler.

    My personal preference would be to print 0 0 0. Then we have a consistent story that not initialising a variable is identical in *behaviour* to initialising it to the default value.

    If we suddenly want to introduce the concept of variables that exist within the scope of a loop block then use a different notation e.g.

    Dim x As Integer = x //you realise this works today, right?

    So if you did what I suggest above, then you could convince the c# team to accept the same (with the same semantics of course) instead of asking “Assignment made to same variable; did you mean to assign something else?”

    Naturally this would promote consistency between the two languages which, as I understand it, goes against the goals of both teams πŸ™‚

    Reply
  30. Mike Gale

    I expect it to produce 012.

    I hope I wouldn’t code that way myself. (Why the readline?)

    I take the Dim x as a compiler directive, not executable code.

    The discussion illustrates one thing. Maybe our languages are too complicated in some way. These few lines generate a lot of discussion, should they?

    On what the output should be. A smart language / IDE might suggest things like:

    "Stop programming immediately…"

    OR

    "I suggest you declare…."

    at coding time. At runtime it’s got to do what the language definition says.

    Reply
  31. Ray Turner

    Reason for my original answer (0,0,0)

    When I use a ‘Dim’ statement two things usually happen:

    1. variable is allocated

    2. variable is initialised to a default value

    This is simple and easy to get used to.

    Now in this case it does not matter if the variable is allocated, it may make sense to reuse it. However either way I believe that there is an implicit contract that on the line following, the varible will be initialised to its default value.

    Now it would make sense for me to explicitly initialise variables in all cases that matter, and this is what I try to do. However for better or worse we might come to rely on the default initialisation. In this case a programmer could take a long time to realise what is causing these unexpected results.

    I like to keep my variables as local as possible, and I am attracted to the idea that the scope of x could be equivalent to the scope of i, but it makes my code less clear and so I think that I would declare x outside the loop any way if I wanted that result.

    Reply
  32. bg

    in vb 6 i believe it would print 0,1,2 because the compiler would move the scope of the variable, which stinks. it should print 0,0,0 because the scope of var x is in the for

    it would be nice if you could do

    For x as integer, i as integer = 0 to 2 …

    Reply
  33. Bill McCarthy

    okay, so now people have tested it, I s’pose we can discuss the "why" ?

    Lets say we have the code call a method in the loop, passing the variable x out by reference ot another method. Suddenly the game changes dramatically. You now need the compiler to allocate an array (or risk overflowing the stack allocation). If we use an array though, I don’t believe you are meant to pass out references to elements…. it’s going to get real messy real soon.

    So it is probably more logical in some ways to not allow that ever expaning list of local varaibles. But the question then becomes is this behaviour obvious, and I think the answer is obviously not. So perhaps a non obtrusive warning is in order (along with a declerative syntax for turnign that eror off if you are sure this is what you want your code to do)

    But this leads to a bigger question. Here we have an artifical scoping, promoting the variable declaration up one level so as it stays alive on each iteration. Yet when we have a Try Catch block we don’t promote the variable or do we ? Consider this variation of Paul’s code:

    Module Module1

    Sub Main()

    For i As Int32 = 0 To 2

    Try

    Dim x As Int32

    Console.WriteLine(x)

    x += 1

    Catch ex As Exception

    End Try

    Next

    Console.ReadLine()

    End Sub

    End Module

    Now igiven the behaviour of x, we would expect we could also access x in the catch block, right ? After all x is actually promoted to outside the For block. yet we cannot.

    So the behaviour is inconsistent to say the least πŸ˜›

    Reply
  34. RolfBjarne

    For me it is quite simple, the variable is declared once, so it is initialized once. (The Dim statement is not an executable statement, if I’m not very wrong you cannot set a breakpoint on it in the debugger). If you want an intialization of the variable, code it!

    I have been using this myself several times when I want a variable with scope only within the current block.

    Reply
  35. Bill McCarthy

    you can set a breakpoint on a Dim statement, and it is an executable statement. It allocates space for the object and sets the object to it’s initial state which in VB is Nothing( null or default in C#)

    Reply
  36. Bill McCarthy

    page 180 of the VB langauge specification says:

    "Variable initializers on local declaration statements are equivalent to assignment statements placed at the textual location of the declaration. Thus, if execution branches over the local declaration statement, the variable initializer is not executed. If the local declaration statement is executed more than once, the variable initializer is executed an equal number of times. "

    this contradicts the behaviour.

    Reply
  37. Geoff Appleby

    Yes, just reading the code and ignoring any preconceived ideas, I’d expect the output to be

    0

    0

    0

    I haven’t run any tests, but I would hope that this is exactly what it does too.

    Reply
  38. Branco Medeiros

    I expect it to print

    0

    1

    2

    That’s because the Dim statement has no initialization indication and therefore the variable will be initialized to its default value when stack space is allocated to it. It seems to me that Dim is an execution statement only when some sort of initialization is explicitly indicated. Therefore, the Dim in the snippet is just a variable declaration (which implicitly clears the area that the variable will occupy, and thus, "initializes" it).

    I can’t aggree with others that say that the compiler should warn about a non-initalized variable. VB’s tradition has allways been to auto-initialize variables with their default value upon declaration, it’s part of its semantic. If other languages require you to manually assign a value to a fresh variable, so be it, but that’s not how VB works. I frawn upon code that says something like "Dim B as Boolean = False". It seems to me as an overstatement.

    Nevertheless, because there’s no explicit inicialization, the variable begins its life with the default value and keeps its last assigned value at each cycle, which is just as it should be, IMHO.

    Reply
  39. Urs

    3 years ago, when I first approached VB.NET, I would expect it to be 0,0,0. Now I know that the result is 0,1,2.

    I stumbled over this exact problem in production code countless times already, until I learned the behaviour to ALWAYS initialise the value inline, such as Dim a As Integer = 0.

    What makes things worse: When you test the code, it often happens that you test the loop only ONCE (because of time constaints) – and the first interation is ok. You only notice it later, in production environment, that actually, the second and third interations don’t work anymore πŸ™

    I would be very glad if the compiler would warn me in this case.

    Reply
  40. Kevin

    It’s gonna print 012, which irritates me. I don’t see any real value in VB Block scope variables. Their lifetime is the same as other variables local to the procedure, but their scope is just within the block. I think their life should be block scope as well.

    At least we can work around this by initializing the variable on every loop.

    Reply
  41. simon geering

    Just reading that through in my head I would say

    0

    0

    0

    because the scope of X is limited to only the current itteration of the loop so the next time round X is a newly declared integer variable with the default value 0.

    Reply
  42. Ricardo Stuven

    "why I’m asking this and why the answer matters at this particular moment in time."

    Hmm… because VB will support closures? πŸ™‚

    Reply
  43. Mike Woodhouse

    I think it will output

    0

    1

    2

    I sorta think it should output

    0

    0

    0

    I would be critical of the person who wrote the code….

    πŸ™‚

    Reply
  44. RolfBjarne

    Bill McCarthy: Had to test it – VS2005 allows you to put on a breakpoint on a Dim statement (without initializers), but when the code is run the breakpoint is moved to the next (executable) statement.

    Regarding the following:

    ******

    page 180 of the VB langauge specification says:

    "Variable initializers on local declaration statements are equivalent to assignment statements placed at the textual location of the declaration. Thus, if execution branches over the local declaration statement, the variable initializer is not executed. If the local declaration statement is executed more than once, the variable initializer is executed an equal number of times. "

    this contradicts the behaviour.

    *****

    the first line says "Variable initializers…". There are no variable initializer in the given code…

    Two paragraphs above the specification says:

    "local variables are initialized to their type’s default value upon each entry into the method"

    which is exactly what is happening.

    I personally prefer the current behaviour, but that might be because I’m used to how vb does it. Though a warning might be a good idea.

    Reply
  45. Bill McCarthy

    Rolf: The document probably does mean explicit variable initializers, but it does not distinguish between explict and implicit initializers.

    I think the current behaviour is undesirable, as the different opinions here lay testimony to. Ideally the language should be clearer on issues like this. Having the IDE or compiler warn on such constructs is really a second best option as that can just lead to excessive noise on a compile, but given the current situation the IDE interacting on such constructs is probably the best we can now hope for.

    I do understand why the compiler does this for a number of reasons including backward compatibility, and the difficulty//almost impossiblity of implementing the variable as a true new allocation on each iteration. At best, it’d probably only be practical to implement it as the one slot that gets re-allocated. Given that constraint, the current implementation does offer some extra functionality, albeit via smoke and mirrors. In doing so I think it confuses some, and does not conform to the block scopign rules, rather the variable is scoped with the outer block (althoguh that is unlikely to bother people as to object lifetime except in some extreme cases)

    So anyway, yes a rule such as "Warn on no explicit variable initialisers inside loop constructs" would possibly be helpful, as well as a <nowarn> attribute that cold be applied. If people do use this syntax, I want it obvious in their code they deliberately are doing so. Honestly, I don’t think there is any real scoping benifit, and in fact it is more prone to errors if you refactor etc. so I owuld be jsut as happy to see the IDE not allow that code, requiring the variable to be declared before the For Next block. doing that would make the code very clear to everyone and we wouldn’t have different interpretations. I think that is the ultimate goal.

    So perhaps the best path forward is a compiler warnign in the next version, or two, warnign that this feature will be made obsolete, and this actual feature be totally deprecated for the sake of code clarity and developer sanity πŸ™‚

    Reply
  46. Tom Bowen

    I assumed it would have output 000. If I had wanted the 012 result, I would have Dimmed it immediately before the For line. For no particular reason other than "It just feels right", I see Dim statements as the birth of the variable, not a continuation.

    Reply
  47. JustinM

    I disagree with the claims that the variable’s Lifetime Scope is different from its accessibility. What we’re arguing over here is the very *definition* of scope.

    If you rewrite the code removing the for loop (unrolling) then you could get :

    Begin Scope of unrolled For loop

    Dim x As Integer

    ‘ x = 0 ‘ If the var has explicit initializer

    Console.WriteLine(x)

    x += 1

    ‘ x = 0

    Console.WriteLine(x)

    x += 1

    ‘ x = 0

    Console.WriteLine(x)

    x += 1

    End Scope

    There’s nothing *wrong* with that per se. It’s just weird to anyone used to the behavior of C++, C#, etc, which is:

    Begin Scope of unrolled For loop

    Begin Scope of For loop contents

    Dim x As Integer

    Console.WriteLine(x)

    x += 1

    End Scope

    Begin Scope of For loop contents

    Dim x As Integer

    Console.WriteLine(x)

    x += 1

    End Scope

    Begin Scope of For loop contents

    Dim x As Integer

    Console.WriteLine(x)

    x += 1

    End Scope

    End Scope

    (Note, I’m not saying that loops are always unrolled by the compiler. I’m just trying to clarify the behavior.)

    However, note that this problematic behavior does not exist for objects or valuetypes. Interestingly this means that the seemingly built-in type Date behaves differently.

    For X As Integer = 0 To 2

    Dim d As Date

    Console.WriteLine(d.ToString)

    d.Add(TimeSpan.FromTicks(1))

    Next

    Prints the same value three times, as do any user defined types.

    So it seems you have a bug somewhere, because the behavior should at least be consistent. From an outsider’s perspective it would seem to be easiest to treat loops the same as in other commonly used languages, but I wouldn’t be too upset if you instead went the other way. Just make it consistent for all types.

    If you *are* going to keep the current behavior then please, just for me, add an option to enable a warning whenever variables within loops are not explicitly initialized.

    Btw, this is not my only problem with VB For loops. http://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?FeedbackId=590bc265-84ac-45a2-a04a-b0b855ebd6ec

    Reply
  48. Chris Kuznicki

    It should be 0, 1, 2 because when you define the variable you are then setting the for loop to run until the result reads 2. After the result is two the for loop closes because the result no longer reads the criteria set forth before the for loop.

    Reply
  49. Tim Hall

    Well i for one cant wait to see what Paul has to say, about the behaviour (especially if its a recomened practice or not, im starting to think not since C# doesnt do the same, and converting from VB to C# could lead to problems).

    I noticed that looking at the IL of the decompiled method. The declarations for both variables (i and x) are made upon entry to the method and hence any more granular scope than the method level seems to only be an enforced rule for clarity rather than technical reasons.

    That i did not expect (i expected the variables to be declared upon entry to the scope that contains it). So i was right but the reason was slightly off.

    Reply
  50. Manish Jadhav

    It’s got to be

    0

    0

    0

    Variable x gets declared (and initialized) within the loop everytime. It’s scope is within the loop.

    Manish Jadhav

    Reply
  51. Bill McCarthy

    JustinM: Re the datetime code. The Add method does not change the intital variable, you’d have to assign it to the variable. So the behaviour you are seeign has nothign to do with loop scope. also, it is unlikely that adding 1 tick would change the date string in general format.

    As ot the comment about objects, no, the behaviour is actually the same for objects, valuetypes and intrinsic types in regardss to scope and loop constructs. Tyr this simple code as an example:

    For i As Int32 = 0 To 10

    Dim obj As Object

    If obj Is Nothing Then

    Console.WriteLine(i)

    obj = New Object

    End If

    Next

    Console.ReadLine()

    Reply
  52. Robert Edwards

    By now we all know the output is

    0

    1

    2

    I thought I understood why. However, add an additional Console.WriteLine(x) after the increment and the output is much different than I would have guessed.

    The two behaviours seem to contradict:

    Module Module1

    Sub Main()

    For i As Integer = 0 To 2

    Dim x As Integer = 0

    Console.WriteLine(x)

    x += 1

    Console.WriteLine(x)

    Next

    Console.ReadLine()

    End Sub

    End Module

    Reply
  53. Tim Hall

    Robert: I wodulk expect your output to be

    0

    1

    0

    1

    0

    1

    Because you put an initializer on the declatation of x, so it would set x to 0 on each loop.

    Reply
  54. JustinM

    Grrr.

    Am I the only one who finds it surprising that System.DateTime is immutable. I always forget this when I haven’t written .NET code for a while.

    Reply
  55. JustinM

    So, I guess we do have consistency. I just had a loose nut on my keyboard. πŸ˜‰

    It’s also interesting to note that you can get the behavior expected from other languages by always using New with value types. (Like C#)

    For i As Integer = 0 To 2

    Dim x As New Integer

    Console.WriteLine(x)

    x += 1

    Next

    Looks a little weird with primitive types though.

    Reply
  56. Tim Hall

    Justin: That would be expected behaviour as

    Dim x as New Integer is shorthand for

    Dim x as integer = new integer which is an initializer, which we know alters the behaviour.

    There are some nifty constructors on some primitives though, integer doesnt have any but string does.

    Reply
  57. Anthony D. Green, MCP

    A poll with some radiobuttons might have been better, I’d really like to see a running tally.

    For the time being I think it should output what it currently does.

    If the code didn’t output 0, 1, 2 – if x were reinitialized each time then it would completely nullify the whole block level scoping. A For loop isn’t repeatedly leaving its own scope and reentering it. All the iterations are in a continuous scope.

    The variable i is also within the scope of the For loop, it doesn’t reinitialize to 0 every iteration.

    Block level scoping is good for reusing the For loop’s imfamous i, j, x, and y variables multipletimes in a procedure and it does save you variable initialization if you have lots of variables and complicated control structures (if ginormous procedures are the kinda thing you’re into).

    As for matching up with C# behavior, I think we’ve burned that bridge a while ago. I resent the implication that C# sets the gold standard for what is and isn’t good practice. While I like them matching each other in capability I also like room for innovation and personality especially where and alternative is provided – that is to say, C# for loops don’t cache their upperbound – can you cache it? yes. Can you make it so that x reinitializes every iteration? yes.

    And as for new programmers being confused? It’s called reading. If they can’t read a paragraph about block level scoping then they really aren’t at the level to be formulating assumptions about programming language behavior.

    Lastly (and this may just be my browser) for the love of Jesus, Mary, Joseph, and all the Saints find a way to make this feedback box wider, PLEASE.

    Reply
  58. JustinM

    Tim, I realize that. I was just trying to point out that vb and c# could be considered consistent with respect to this feature, except that c# doesn’t allow declaring valuetypes without initializers.

    I’m glad Paul brought this up, because I didn’t know it.

    Reply
  59. Tim Hall

    Justin: Sorry i didnt even see the (Like C#) bit there, i guess as usual my eyes jumped to the source code before finishing reading the preceeding text πŸ™‚

    Reply
  60. Mike Griffiths

    Only

    0

    0

    0

    will do as it is all about Scope and the scope of this declaration is "inside" the loop.

    I like variables to have a potentially confined scope within routines – the alternative is to consider the Dim statement was at the top of the sub/function but that was no where the programmer put it.

    Reply
  61. Mike Galos

    I think it should error out with a runtime error for declaring an already declared variable (in the time honored tradition of needing a redim statement)

    Of course, that’s not what it DOES do but…

    Reply
  62. David Conrad

    Although Java on an MS VB thread will probably be about as popular as a New York strip steak at a vegetarian buffet, I’d like to share a perspective from another programming language.

    0, 0, 0

    is what makes sense to me, and here’s why. It does seem to me that the for loop’s scope is being entered afresh each time around the loop. Consider the following Java program:

    public class Sevens {

    public static void main(String[] args) {

    for (String s : args) {

    final int x = Integer.parseInt(s) * 7;

    System.out.println(s + ": " + x);

    }

    }

    }

    We iterate over the command line parameters, converting each one to an int and multiplying by seven. Notice that the variable x’s scope is confined to the loop, and that it is declared "final", meaning that it cannot be changed once it has been set.

    At first blush you might think this is not a legal Java program, but in fact it is, and does just what you would expect. Of course, one big difference may be that it is the BLOCK of the for loop (the curly braces) that introduces a new scope. If the understanding is that in VB it is the FOR keyword itself introducing the scope, I can see why one would argue that the scope is not being exited and entered each time around the loop.

    I hope this outsider’s perspective is of some benefit. Consider it grist for the mill.

    Reply
  63. Xandy

    Well i’m a noob in the vb.net world yet… but, the logical answer according the documentation is 000… the local scope of var force the initialitation…

    Reply
  64. Eric D. Burdo

    >>Do I want the compiler to be "smart" and know that it only has to create and initialize the variable once? Do I want the compiler to be literal and initilize the variable each time through the loop? Or do I want the compiler to be brain dead and give me an error?

    I would prefer the compiler be brain dead. If the code is ambiguous, then warn me and don’t compile. That way I have to write what I want it do do… clearly and concisely.

    Reply
  65. Richard

    Here’s a further thought – if you try:

    For i As Integer = 0 To x

    Dim x As Integer

    Console.WriteLine(x)

    x += 1

    Next i

    the first line doesn’t compile – x isn’t in scope.

    Hmm – x is in the scope of the for loop, and so is i, but they’re not in the same scope… we have scopes like this:

    Module

    Sub

    For + Next

    For loop contents

    Also, to show how much of a special case the for loop is, try the functionally equivalent:

    Do While i As Integer <= 2

    Dim x As Integer

    Console.WriteLine(x)

    x += 1

    i += 1

    Loop

    Reply
  66. Thomas Hall

    I’m a VB.NET guy and I agree with those who believe it should output:

    0

    0

    0

    Since it is declared within the body of the For…Next statement, the scope of x should be within the body of the loop and therefore initialized for each pass through the loop. x should not be in scope when the For…Next statement counter is evaluated.

    Reply
  67. Pingback: Panopticon Central

  68. Pingback: Panopticon Central

Leave a Reply