Consulting

Page 1 of 2 1 2 LastLast
Results 1 to 20 of 23

Thread: Buggy scope of a variable

  1. #1

    Buggy scope of a variable

    I have code as follows (yes, it's pseudo-code).
    [VBA]
    For i = 1 to 5
    Dim j As Integer
    ' j = 0
    j = j + 1
    MsgBox j
    Next i
    [/VBA]

    I'd expect one and the same value to be redisplayed all the five times. It doesn't happen; the j grows gibber for every loop-run.

    Now, in ANY normally working and self-respecting language i've ever met, the variable j will be out of scope at the end of the loop-run. Not in VB. On the other hand, the complainer does compile the code and let's me (re?)declare the variable... That's a new one too...

    What's going on here? Is the variable redeclared at every loop-run and if so - why does it retain it's value, if not - why doesn't it nag?!

  2. #2
    Distinguished Lord of VBAX VBAX Grand Master Bob Phillips's Avatar
    Joined
    Apr 2005
    Posts
    25,453
    Location
    Why would you expect the code to increment the variable but the variable value does not change? That seems pervers in the extreme to me.

    I know not what languages you refer to that, but the variable is in scope for the whole of the procedure/module/application that it is declared within, as it does with all other languages that I know. I have come across some where the value of a loop index is not guaranteed after exiting a loop, but VB/VBA is not one. So what? Why do you expect everything to be the same as some other (obscure?) language that you have experienced?
    ____________________________________________
    Nihil simul inventum est et perfectum

    Abusus non tollit usum

    Last night I dreamed of a small consolation enjoyed only by the blind: Nobody knows the trouble I've not seen!
    James Thurber

  3. #3
    Administrator
    Chat VP
    VBAX Guru johnske's Avatar
    Joined
    Jul 2004
    Location
    Townsville, Australia
    Posts
    2,872
    Location
    No, it's not redeclared at each loop-run. It's only declared the once (and that's normally at the head of the code) with the Dim statement. THIS is declaring it twice - try to run that and Visual Basic will complain

    [vba]
    Sub aaa()
    Dim i As Long
    Dim j As Integer
    Dim j As Integer

    For i = 1 To 5
    ' j = 0
    j = j + 1
    MsgBox j
    Next i
    End Sub
    [/vba] the good news is that the writers of Visual Basic anticipated that there may be some idiots who would try to declare a variable inside a loop and have built in error handling to handle that situation - now that's good coding eh?
    You know you're really in trouble when the light at the end of the tunnel turns out to be the headlight of a train hurtling towards you

    The major part of getting the right answer lies in asking the right question...


    Made your code more readable, use VBA tags (this automatically inserts [vba] at the start of your code, and [/vba ] at the end of your code) | Help those helping you by marking your thread solved when it is.

  4. #4
    Distinguished Lord of VBAX VBAX Grand Master Bob Phillips's Avatar
    Joined
    Apr 2005
    Posts
    25,453
    Location
    Quote Originally Posted by johnske
    No, it's not redeclared at each loop-run. It's only declared the once (and that's normally at the head of the code) with the Dim statement. THIS is declaring it twice - try to run that and Visual Basic will complain

    [vba]
    Sub aaa()
    Dim i As Long
    Dim j As Integer
    Dim j As Integer

    For i = 1 To 5
    ' j = 0
    j = j + 1
    MsgBox j
    Next i
    End Sub
    [/vba] the good news is that the writers of Visual Basic anticipated that there may be some idiots who would try to declare a variable inside a loop and have built in error handling to handle that situation - now that's good coding eh?
    I see what he means about redeclaring now that I see your answer. It never occurred to me that someone might think that putting the Dim statement within the loop meant it would be refreshed each iteration, it just seems so obvious to me that it is just declaring the variable. After all, the compiler does its stuff BEFORE the run.
    ____________________________________________
    Nihil simul inventum est et perfectum

    Abusus non tollit usum

    Last night I dreamed of a small consolation enjoyed only by the blind: Nobody knows the trouble I've not seen!
    James Thurber

  5. #5
    Chamster,
    My two cents. It seems to me that you really mean reset the variable, not redeclare. You wrote about it remaining in scope after the loop has completed its instructions. As Bob and John wrote, in other words, the variable is assigned to memory and the type of variable once you declare it, the value is something entirely different.
    This is where w/inside the loop if you wanted a different value, you would reset it, not redeclare it.
    my site: www.ecboardco.com
    was built w/ a majority of the assistance from the board members here... thanks VBAX.

    Just because I see something, doesn't mean that what's actually happening is what I see.

    You don't get from 0-90 by standing still!

  6. #6
    Hmmm... This will be interesting, i think. C++ and Java syntax will be in this example as follows.

    for (int i; i <= 5; i++) {
    int j;
    j++;
    std::cout << j << std::endl; // for C++
    System.out.println (j); // for Java
    }

    Every time one enters the loop there will be a new declaration of j, hence killing the stored value. In fact, the value will be garbage collected already at the closing bracket.

    Of course, since it's required not to use uninitialized variables, we'll get errors but as pointed out above - it's pseudo-code, to show my point.

    Perhaps i'm unclear about the exact result of a Dim-clause. I thought it was a declaration. Since it's being done multiple times, i'd expect it to do exactly one of the below.
    a) Crash, boom and bang caused by a redeclaration.
    b) Reinitialization due to a new declaration as the variable went out of scope.
    Last edited by chamster; 09-25-2007 at 05:21 AM.

  7. #7
    VBAX Master
    Joined
    Jun 2007
    Location
    East Sussex
    Posts
    1,110
    Location
    That is true and I take your point, but VB/VBA does not work that way. (and you can't use ReDim to redeclare the variable either) Just one of those things.
    Regards,
    Rory

    Microsoft MVP - Excel

  8. #8

    Thumbs down

    Quote Originally Posted by rory
    That is true and I take your point, but VB/VBA does not work that way. (and you can't use ReDim to redeclare the variable either) Just one of those things.
    Are you implying that there's actually a "protective" clause somewhere in the deeps of source code for VBA that will change the declaration to only be executed once and then skipped over every time i intentionally re-execute it, by assuming that i ment otherwise?!

    Rule numero uno of variable declaration is to do so as close to the actual usage point as possible (the other school is to declare everything at the head of the method, i know, i know). It's stated everywhere from the Bible, the Coran, Karmasutra to the manual of my motorcycle!

    Well, as long as i know it's this way in VBA, i can live with that. Perhaps i'm too damaged with previous experience to do this job...

  9. #9
    VBAX Master
    Joined
    Jun 2007
    Location
    East Sussex
    Posts
    1,110
    Location
    Yup!
    Rule number 2 is not to rely on implicit initialisation (which is what you are doing) and to explicitly initialise any variable that you use. It serves no purpose to repeatedly declare the variable's interface/data type, after all. All you need to do is add a j=0 line.
    If you can do C++, VBA should be a piece of cake, other than the odd curve ball... No pointers to worry about (unless you want to).
    Regards,
    Rory

    Microsoft MVP - Excel

  10. #10

    Question

    Quote Originally Posted by johnske
    No, it's not redeclared at each loop-run. It's only declared the once (and that's normally at the head of the code) with the Dim statement...
    ...the good news is that the writers of Visual Basic anticipated that there may be some idiots who would try to declare a variable inside a loop and have built in error handling to handle that situation - now that's good coding eh?
    At first i thought you were sarcastic. Now, that i read the other posts, i'm starting to fear that you actually think it's a good idea. I guess it's a matter of taste (good or bad, let's not get into discussion about whos is which, ). So, how should one go about if one actually does want to declare a variable inside a loop? I'm assuming it's possible. Should i not?

  11. #11
    Quote Originally Posted by rory
    Yup!
    Rule number 2 is not to rely on implicit initialisation (which is what you are doing) and to explicitly initialise any variable that you use. It serves no purpose to repeatedly declare the variable's interface/data type, after all. All you need to do is add a j=0 line.
    If you can do C++, VBA should be a piece of cake, other than the odd curve ball... No pointers to worry about (unless you want to).
    I went something like
    [VBA]
    Dim d as Double
    d = 0
    [/VBA]
    and got corrected just a few days back on this very forum as d was supposed to get the value of zero by itself. I'm feeling a bit misguided here. Now that i think of it, i believe i understand what was ment.

    I'd also argue that it sure serves a purpose to declare/gc/redeclare because you're freeing system resources. On the other hand, for speed sake, perhaps one shouldn't use VBA in the first place...

  12. #12
    Distinguished Lord of VBAX VBAX Grand Master Bob Phillips's Avatar
    Joined
    Apr 2005
    Posts
    25,453
    Location
    Ever hear of garbage collection?
    ____________________________________________
    Nihil simul inventum est et perfectum

    Abusus non tollit usum

    Last night I dreamed of a small consolation enjoyed only by the blind: Nobody knows the trouble I've not seen!
    James Thurber

  13. #13
    VBAX Master
    Joined
    Jun 2007
    Location
    East Sussex
    Posts
    1,110
    Location
    It may well do, but you don't have any say in when (or if) VBA does its garbage collection.
    Although most people don't bother with explicit initialisation of variables (as opposed to resetting them), I'd be surprised if someone told you you shouldn't do it!
    Regards,
    Rory

    Microsoft MVP - Excel

  14. #14
    Perhaps i misunderstood that person. Still, to me it looks like a redeclaration and should be reported by the compiler as an error not hidden behind some "let's help the idiots"-approach.

    Thanks for everybody for helping, by the way.

  15. #15
    Administrator
    Chat VP VBAX Guru johnske's Avatar
    Joined
    Jul 2004
    Location
    Townsville, Australia
    Posts
    2,872
    Location
    The Dim statement declares variables and allocates storage space i.e. it 'creates' a variable.

    Once a procedure level variable has been declared/created it's available for the life of the procedure and that's its' scope - a procedure level variable has the smallest scope (it may help you to read the VBA help files regarding scope in Visual Basic)

    Once created, the procedure level variable's only destroyed (released from memory) when the procedure ends. The created variable is thus quite robust and you cannot just destroy/create, destroy/create willy-nilly like you seem to be trying to do (and i completely fail to see any point in trying to do that either - if you're worried about memory, you can effectively 'redeclare' variables by reinitializing them, i.e. put your long/integer variable equal to zero, your string variable equal to "", your variant variables equal to empty, set your object variable equal to nothing, etc... {but all that's just over the top IMO})
    You know you're really in trouble when the light at the end of the tunnel turns out to be the headlight of a train hurtling towards you

    The major part of getting the right answer lies in asking the right question...


    Made your code more readable, use VBA tags (this automatically inserts [vba] at the start of your code, and [/vba ] at the end of your code) | Help those helping you by marking your thread solved when it is.

  16. #16
    Mac Moderator VBAX Guru mikerickson's Avatar
    Joined
    May 2007
    Location
    Davis CA
    Posts
    2,778
    If Excel VBA were interpreted rather than compiled, multiple type declarations might make sense.

    Dim (like Sub and End Sub) are more instructions TO the compiler than instructions for the compiler to act on.

    ReDim, on the other hand, is an instruction at the same level as Set, DateSerial and most other VB statements. Use dynamic arrays (Dim myArray() as Integer) and ReDim will act the way you want Dim to.

  17. #17
    Administrator
    Chat VP VBAX Guru johnske's Avatar
    Joined
    Jul 2004
    Location
    Townsville, Australia
    Posts
    2,872
    Location
    Addendum to post #15...

    Note that these variables are automatically destroyed as they go out of scope, so there is no need for you to destroy them, with one exception...

    Application-level object variables used in conjunction with the New keyword or application-level object variables created using 'CreateObject' are not automatically destroyed, and these do need to be set equal to nothing by the coder.

    {Application-level object variables as described above are used to create and open new (maybe 2nd, 3rd, etc) hidden instances of another application such as Word, PowerPoint, etc.}
    You know you're really in trouble when the light at the end of the tunnel turns out to be the headlight of a train hurtling towards you

    The major part of getting the right answer lies in asking the right question...


    Made your code more readable, use VBA tags (this automatically inserts [vba] at the start of your code, and [/vba ] at the end of your code) | Help those helping you by marking your thread solved when it is.

  18. #18
    Quote Originally Posted by johnske
    The created variable is thus quite robust and you cannot just destroy/create, destroy/create willy-nilly like you seem to be trying to do (and i completely fail to see any point in trying to do that either)...
    Perhaps it's a matter of coding conventions. The golden rule i've been to use is "if you're not using it (right now), don't occupy it". I guess it's of more importance if you're on a system with scarse resources. Or, perhaps, it's a matter of taste or langauge. I'm not exactly an expert at VB so my surprise is by comparison to other languages, not implying that it's valid in VB.

    Quote Originally Posted by johnske
    Once a procedure level variable has been declared/created it's available for the life of the procedure and that's its' scope - a procedure level variable has the smallest scope...
    If you say so. I can use it that way, no problems. Still, the idea of such a limitation (not being able to control the scope into the tiniest detail by myself) feels unfamiliar to me. On the other hand, it's not exactly a deal breaker, just an unusual approach. I guess that explains why my
    [VBA]
    For i = 1 As Integer To 5
    [/VBA]
    didn't work (except for the syntax, that is). According to you, i couldn't be able to declare the integer i with scope of the for-loop anyway. I think i get the general idea. Thanks.

  19. #19
    Quote Originally Posted by rory
    It may well do, but you don't have any say in when (or if) VBA does its garbage collection.
    Although most people don't bother with explicit initialisation of variables (as opposed to resetting them), I'd be surprised if someone told you you shouldn't do it!
    I started to fear that i began to "develop facts" so i went browsing and i've found the post. It's in "Declaring a variable and assigning a value to it at once" at http://www.vbaexpress.com/forum/showthread.php?t=14987, the third post.

    However, before we start scratching eachothers eyes out, i can calm the situation by pointing out that it was an misunderstanding. Norie ment that initialization wasn't needed but that was most likely under assuption that the example was to be placed in the beginning of a method (rightfully so, according ro Johnske). So, i guess there's no problem anymore.

  20. #20
    VBAX Master
    Joined
    Jun 2007
    Location
    East Sussex
    Posts
    1,110
    Location
    As we have seen, it doesn't matter where the Dim statement is - initialisation of a variable only occurs once per procedure, and at this point, your integer will be given an initial value of 0. Whether this is true in the future we don't know (though it seems likely to me that numeric values would be initialised as 0) so it's probably better to explicitly assign the value you want in your code; for the example you have cited, you have no choice but to do that!
    It has, I think, long been known that VB(A) does not give you the low-level control of something like the C languages; on the other hand, it's a hell of a lot easier to code in for most people. If you want to use C++, create .dll or .xll files for use with Excel?
    Regards,
    Rory

    Microsoft MVP - Excel

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •