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

Leave a Reply

Your email address will not be published. Required fields are marked *