STACK_VAR vs LOCAL_VAR
mjones2620
Posts: 86
Still trying to wrap my head around the difference. Could someone explain in further detail than what's listed in the help, when one would be preferred over the other?
0
Comments
A Stack and Local variable is a variable name that only applies within the brackets they exist. the nice thing about them is they can be resued all over the place since you can think of them as being Function_X:myStackVar and FunctionY:MyStackVar. you can have multiple instances of MyStackVar all over your code but they stay descrete to each set of braces they live.
So, if you have something like this:
In this example I've used the variable name tp_id twice. but they will never stomp on each other since they only exist within the braces of the push event. If I hit TP id 1's button 1 and TP_ID2's button 2 - the stack vars tp_id will be differnt in the two different button events.
The reason this is handy is it allows me to do quick copy/pastes (whicd I did in this example to get my second button event) without haveing to change a bunch of code.
Now - having set this table - here's the differnec between a Stack Variable and a Local Variable.
a stack_var resets to zero every time you leave the set of braces they live in. A local_var retains its value throughout runtime. So, if you find yourself needing to hang on to the value of the variable for later use, then you use a local_var. If you don't care if it goes away and don't need it again until the next time you hit the braces, then use a stack_var.
And examle of this is if you put a wait in the button_event that requires the value you grabbed.
example
^^ This won't work because the value of tp_id goes back to zero by the time the 5 seconds pases. so you'd basicall be saying "Send a double-beep command to the zero-th TP" doesn't work.
^^ This WILL work since the local_var will have the value still after 5 seconds. local_vars hng on to their values after you leave the braces.
Make sense?
e
So if two different touch panels hit button 1 within five seconds, which touch panel will get the second beep, the first or the second?
Paul
Isn't it th case that you CAN see a stack_var value if you put a stop/breakpoint there and pause runtime in debug?
To make it easy for our guys to program, I tell them that
stack_var are variables that get created and destroyed upon event starting and finishing.
local_var are variables that get created upon event starting and are retained for that event in the future.
In general I don't use local_vars much at all.
Regards
Craig
Paul,
In the case you describe it will equal the s cond hit. In that regard this is not a good example. The example is sufficient to explain the way it works I thimk. But not a very good use in practice.
Agreed,
I rarely use local_var. and stack_vars are always "throw away" stuff.
Yes that was I thought. Doing feedback to panels using waits is tricky because a stack_var only exists for a short period of time, and a local_var's value can change before the wait occurs giving erroneous behavior.
Paul
Yep, like I said, on many levels it's not a good example of a real-world use. Just a silly one to try and help illustrate how it works.
define_function integer fnGfjadj(INTEGER _ddd) {
local_var integer notGlobal
notGlobal = notGlobal + _ddd
return notGlobal
}
x = fnGfjadj(1)
why? i don't know
LOCAL_VAR is in the data segment. This variable is statically allocated once at compile time.
For most architectures, using a variable on the stack can be faster than using one in the data segment, making STACK_VAR faster. NetLinx isn't an interrupt-based system and I'm not sure how it handles optimization and variable stores/loads, but some informal tests validate this claim. Not like it matters, most of my systems have ~5% cpu usage, but "efficiency" was muttered around here for a while.
The type of variable will also matter if you are writing recursive functions.
Interesting perspective. I had a better understanding of usage for Stack/Local from the replies above, but I am wondering if this may be causing performance issues on my NI-700. I am using a TON of loops and functions for certain button presses and my processor isn't working correctly.
For example, I have one button that looks like this:
The variables do not get initiated on the first button press. If I press it two more times, it then initiates the variables.
Also when using functions, if they have waits in them and you pass in a stack var it won't work and you won't get a compiler error like you do trying to use a stack inside a wait when you do that inside the braces where the stack in defined.
You can define a LOCAL_VAR inside the function and copy the value of the parameter to get around this. However, subsequent calls to the function before the wait expires will overwrite the value. And if you don't name the wait, cancel it, and restart it, the "SEND_STRING 0" will execute once with the latest value at the wait time from the first call.
To me this is a good reason to use a timeline instead, if you can overlook the fact that timelines are finicky with variables for the timeline ID.
I have found recursion to be somewhat problematic with NetLinx. Nobody in Tech support could give me a definitive answer on how to figure out the depth limitation. Some said it was a fixed number that they didn't know, others said it was based on memory. An alphabetical Bubble sort on 400 items would reach the limit, pre sorting by first letter then bubble sorting each letter group usually worked.
But back to STACK_VARs...
I use STACK_VARs as much as possible. 99.9% of the time all my function variables STACK_VARs (every so often you need a LOCAL_VAR). I have seen way to much NetLinx code with tons of global variables that cause very weird interactions that are hard to track down.
Building a queue to handle waits can be a bit tiresome but if you've done it once, the work is over and you can ensure you don't stomp on yourself.
You can watch stack vars in debug too if you put in break points and step through your code but I haven't done that in years, it's too flaky, instead I tend to use more send_string 0's than one would think necessary and then as I start to debug my code I usually add more because I didn't have enough or have them in the right places.
I also added the ability to turn all Debug Channels off via one Channel. With this I can control any Type of Debug Info I need without recompiling. With all of the systems I have done I have not noticed any hit on functionality or speed. If the Debug Channel is ON the messages are sent via "Send_String 0", if it is OFF the function just returns to the calling function...
Each function call also passes the line in the code where it exists so it easy to find that section. Since some debug strings exceed the length available in a send_string 0 my function also breaks the string it gets passed into multiple lines if necessary and my send_string 0 indicates the line number so again it's easy to tell the lines in diag that are part of the same debug string. When I have my debug calls in switch cases or select active I usually use the default or active(1) if they have no other purpose to print out values that I didn't create a case or active handler for so as I debug I'll find things the device sends that I did plan on and then add them in even if action is required or desired.
Beginning of function so I can check values coming in: Through out the function at vatious stages: The print oun in diagnostics.
My debug function:
This ins't typical since I made this one to maximize the length of the printed string, normally 1/2 this stuff isn't in my function and I just sent the line length to 100 but with this server I get some long strings so I want as much on one print out line as possible.
Agreed. I wrote that just for completeness but I tend to avoid recursion on NetLinx. I've never seen anyone else use it in wild NetLinx code but that's probably the nicest thing I can say about wild NetLinx code...
Now THIS is the good ole AMX Forum that I know and love!