Jump to content
Sign in to follow this  
Tankbuster

variables in loops and scope?

Recommended Posts

Guys, please help me to understand this.

If I create a variable using private at the top of a script, then assign it a value, in this case, true how does that variable behave in loops further down.

(code below is representative and not actually deployed like this. Syntax NOT guaranteed)

private ["_tankyvariable"];
_tankyvariable = true

{
loop
if (condition) then {_tankyvariable = true} else {_tankyvariable = false};
} forEach _this;

if (_tankyvariable == true) then something;
if (_tankyvariable == false) then something different;


Am I making a basic error here? Is the state of _tankyvariable inside the loop completely independent of _tankyvariable outside the loop in the last two lines?

Thanks,

Tanky -Paul-

Share this post


Link to post
Share on other sites

I never use private, almost never as i rely much on changing variables and i dont fully understand the ues of it either.

But gist of it, you can change it on the outside and bring it with you innwards, but any changes inside, will not follow to the outside.

So your example will always return true at the end no matter what happens in the above loops.

The example on BIKI shows this really well.

_foo = 10;
if (true) then
{
   private ["_foo"];
   _foo = 5;
   player sideChat format ["%1", _foo];  // here its 5.
};
player sideChat format ["%1", _foo];  // here its 10.

In this example, the first sidechat (innermost) returns 5 while the second sidechat (outermost) returns 10.

Share this post


Link to post
Share on other sites

You can still use private in the outermost scope where you set the variable.

Whenever you say private ["someVarName"]; you tell the interpreter that the "someVarName" from now on is another one that what is previously in a more outer scope. From this scope and any deeper scopes any changes to "someVarName" will be done on this inner one and the outer one will not be touched. If you somehow need this "name" again and don't want to change some existing more "outer" variable with the same name you use the private command again.

Basically if you want to change some outer variable then don't use private. If you need this name, eg. it makes code more readable then use private.

Share this post


Link to post
Share on other sites

Thanks guys, that's much clearer now.

If I understand correctly, the same variable is in use at the level the private statement is *and every scope further in*?

Share this post


Link to post
Share on other sites
...If I understand correctly, the same variable is in use at the level the private statement is *and every scope further in*?

Yes, that should be the case. It should remain the same unless you again use private in an even deeper scope.

Share this post


Link to post
Share on other sites

As pointed out, if you don't use private, more outer scopes variables could be modified and probably cause issues.

Code is often called from within other code (and so on), so even though you might not see a possible clash at first sight, it's best to always private all variables you're going to use and have no specific intent to overwrite variables in more outer scopes.

Share this post


Link to post
Share on other sites

Ah. I could private it again, deeper in? I hadn't thought of that.

Thanks everyone, much appreciated. :)

Share this post


Link to post
Share on other sites

Yes. Scope for the variable is where it was defined and any inner code. Using the private command tells it to ignore definitions of the variable from the outer code and just re-define the variable for the current scope, thus creating 2 separate variables (one for each scope).

So basically if you want the inner code to overwrite the values defined outside don't use private inside. If you want it to be an independent variable then use private. And in any case, at the start of every script, it's best to use private for anything that really should only exist in the current script, so that you don't accidentally overwrite values of variables that were defined in the calling script (again, unless that's what you actually want to do, though then again when you actually use separate functions/scripts it's probably good practice to not have them share private variables).

Share this post


Link to post
Share on other sites

I just thought I'd add that IMHO it is good practice to use private unless it is necessary to omit it.

If you are writing functions for more complex systems or for other people having the habit of putting a private statement at the beginning of each scope can save you/them a lot of debugging headaches.

Edited by mrCurry

Share this post


Link to post
Share on other sites

When you actually want the opposite result... Which is usually not the case.

Share this post


Link to post
Share on other sites

Example:

    private "_i";
   _i = 12;
   { private "_i"; _i = random 100; diag_log [_x, _i] } forEach ["a", "b", "c"];    
   // _i is still 12

vs

    private "_i";
   _i = 0;
   { diag_log [_x, _i]; _i = _i + 1;  } forEach ["a", "b", "c"];    
   // _i is 3
   diag_log ["Total Entries:", _i];

On a side note: In the first example, if you wouldn't need "_i" in the outer most scope, then only setting private "_i" in this scope suffices, no need to set it also in the forEach scope. Yet still it might be considered better practice to do it anyway.

Edited by Sickboy

Share this post


Link to post
Share on other sites

_somefunc = {
private "_variablethatshouldNOTbechanged";
_variablethatshouldNOTbechanged = 1000;
_variablethatshouldbechanged = 10;
_anothervariablethatshouldbechanged = 100;
};

_variablethatshouldNOTbechanged = 2;
_variablethatshouldbechanged = 1;
_anothervariablethatshouldbechanged = 1;

call _somefunc;

diag_log ["_variablethatshouldNOTbechanged", _variablethatshouldNOTbechanged, "_variablethatshouldbechanged", _variablethatshouldbechanged, "_anothervariablethatshouldbechanged", _anothervariablethatshouldbechanged];

Result:

["_variablethatshouldNOTbechanged",2,"_variablethatshouldbechanged",10,"_anothervariablethatshouldbechanged",100]

Edit: lol, SB was also adding an example :D

Xeno

Share this post


Link to post
Share on other sites

Ah, ok. Kinda misunderstood. I tend to look at it the other way, as shown. Like use private on the outmost scope (not needed, but to make it tidy), then in the inner ones I only make them private if I don't want them to affect the outer result.

However, I prefer as much as possible to use unique names for multiple counters, than using the same one where I have to carefully monitor how scope affects it.

I remember actually getting into problems with it using ruebe's shellSort algorithm, as I used a _i parameter as well, that was forgotten in the function code. I'm not a programmer, so trying to follow recursive code and what the heck is going on, l became blind that the error might not be my own fault (this time :)).

Huh, cool. Haven't seen that diag_log method before. Always relied on format. Thx.

Share this post


Link to post
Share on other sites

Huh, cool. Haven't seen that diag_log method before. Always relied on format. Thx.

I'd assumed that would work but like you, always used format too. :) Funny how you learn new stuff at a time your being taught something else. :)

I never expected such eminent coders to come and help with such an elementary question. Then the same guys show the cunning way that private can do cool stuff. I'm very grateful, guys. Sometimes, this community rocks hard. :)

Share this post


Link to post
Share on other sites

I prefer to not have to think about name duplicates and just use the private command at the start of the scope. That's the some of the point of using private variables (that, and of course them not being saved outside the scope).

Share this post


Link to post
Share on other sites

There's another case where you can use private to let's say "predefine" a local variable so that a value can be assigned in another scope:

private "_myPrivateVar";

if (true) then {
_myPrivateVar = 1;
} else {
_myPrivateVar = 2;
};

diag_log ["_myPrivateVar", _myPrivateVar];

(result is 1 of course).

If you remove "private "_myPrivateVar";" then diag_log _myPrivateVar will return any/nil.

Though I personally try to avoid such constructs as it is not the cleanest and best way and can lead to other problems as the private "_var" alone still doesn't assign any value to the variable (the variable is still nil).

Better would be:

_myPrivateVar = if (true) then {1} else {2};

Xeno

Share this post


Link to post
Share on other sites

Another scope issue is calling a function without arguments:

hintArg = {
   private ["_msg"];
   if (count _this > 0) then {_msg = _this select 0;} else {_msg = "DefaultMsg";};
   hint _msg;
};

someScript = {
   private ["_numbers"];
   _numbers = _this;
   //..... blah blah
   //hint default msg
   call hintArg; //Will probably error
   //...
};

Here we call hintArg without any parameters and you will not get the expected result since hintArg will use the '_this' in someScript and fail since it cannot hint a number. However, if you use [] call hintArg it will work.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×