Home   Help Search Login Register  

Author Topic: Scope of variables in switch statement  (Read 4507 times)

0 Members and 1 Guest are viewing this topic.

Offline Tyger

  • Former Staff
  • ****
  • I was at OFPEC when it still had dirt floors...
    • OFPEC
Scope of variables in switch statement
« on: 08 Dec 2008, 08:52:13 »
First, lets take a look at the code...  :blink:

Code: [Select]
// Unit with type of AmmoBoxWest is input into script
_unit = _this select 0;
switch (typeOf _unit) do {
    case "AmmoBoxWest": { _rndsType = "B_556x45_Ball"; _offsetPlane = 0.5; _offsetVertical = 0.25; hint format["Type: %1 \nOffset XY: %2 \nOffset Vertical: %3", _rndsType, _offsetPlane, _offsetVertical]; };
    case "Truck5tReammo": { _rndsType = "B_556x45_Ball"; _offsetPlane = 0.5; _offsetVertical = 1; hint format["Type: %1 \nOffset XY: %2 \nOffset Vertical: %3", _rndsType, _offsetPlane, _offsetVertical]; };
};

Sleep 2;
hint format["Type: %1 \nOffset XY: %2 \nOffset Vertical: %3", _rndsType, _offsetPlane, _offsetVertical];
exit;

This returns:
Quote
Type: B_556x45_Ball
Offset XY: 0.5
Offset Vertical: 0.25
-----------
Type: scalar bool array string 0xe0ffffef
Offset XY: scalar bool array string 0xe0ffffef
Offset Vertical: scalar bool array string 0xe0ffffef

So, why does the switch statement declare all variables first defined local to it's scope? When I tested it with a for loop, the same happened. The variable I declared inside the for loop was local to the for loop. Is the scope of a variable in ArmA local to a code block i.e. { block }?

Solving the problem is not the issue. A simple declaration of
Code: [Select]
private ["_rndsType","_offsetPlane","_offsetVertical"];
at the start of my function rectified my problem. But I would like to understand how ArmA handles the declaration of variables and what scope ArmA binds a variable to.

Unless my recollection of C/C++, Java, and C# which I learned at college (university for those of you over the big pond) has been forgotten in the 12mo that I haven't used it, a variable declared inside of a while, for, or switch statement was local to the function, not the statement...
"People sleep soundly at night only because rough men stand ready to do violence on their behalf." - George Orwell

MSG Mike Everret - We Will Never Forget - '75-'08

Offline Mandoble

  • Former Staff
  • ****
    • Grunt ONE and MandoMissile suite
Re: Scope of variables in switch statement
« Reply #1 on: 08 Dec 2008, 09:04:40 »
Probably this will happen within any control block (whiles, fors, switch cases).
You have two options:
1 - Initialize the variables outside the block with a default value.
2 - Declare them with private at the beginning of the script.

Offline Tyger

  • Former Staff
  • ****
  • I was at OFPEC when it still had dirt floors...
    • OFPEC
Re: Scope of variables in switch statement
« Reply #2 on: 08 Dec 2008, 09:09:20 »
That is an odd way to do variables... I wonder if it was intentional? I suppose it forces a variable to be declared at the initialization of the function if one wishes it to be local to the function and not to the code block.
"People sleep soundly at night only because rough men stand ready to do violence on their behalf." - George Orwell

MSG Mike Everret - We Will Never Forget - '75-'08

Offline Planck

  • Honoured
  • Former Staff
  • ****
  • I'm never wrong ....I'm just not always right !
Re: Scope of variables in switch statement
« Reply #3 on: 08 Dec 2008, 14:52:08 »
Aye I suspect this was by design as it would be pretty hard to do this by accident I think.

btw.  Welcome back to OFPEC.   :yes:


Planck
I know a little about a lot, and a lot about a little.

Offline hoz

  • OFPEC Site
  • Administrator
  • *****
Re: Scope of variables in switch statement
« Reply #4 on: 08 Dec 2008, 18:22:44 »
In ArmA II  BI has already stated that you will be required to initialize the variable before you can use it.
Xbox Rocks

Offline Ext3rmin4tor

  • Members
  • *
Re: Scope of variables in switch statement
« Reply #5 on: 08 Dec 2008, 19:07:54 »
You don't remember well, a variable inc C/C++ and Java declared inside a control structure exists within the control structures i.e. its scope is the control structure itself. The same happens in .sqf language code blocks: if you declare a variable inside the code block the scope is the code block, outside you can declare a variable with the same name (of course the previous one is lost when exiting the code block). The only difference between C-like languages and the .sqf syntax is that control structures are not part of the language syntax but they are simple commands. In fact if you pay attention at control structures syntax you will understand that they are commands which have as parameters "code block type variables". Blocks in SQF syntax are normal variables like any other. For example the FOR control structures receive as parameter an array containing 3 block type variables (initialization, exit condition and step action).

Besides this fact (that blocks are simple variables) allows you to declare local functions inside a script by simply assigning a block to a local variable like this:

Code: [Select]

_localFunction =
{
//function code

};


Then you can call your local function with the "call" command:

[argument array] call _localFunction
« Last Edit: 08 Dec 2008, 19:12:14 by Ext3rmin4tor »
How can you shoot women and children?
Easy! Ya' just don't lead'em so much! Ain't war hell?!!

Offline Tyger

  • Former Staff
  • ****
  • I was at OFPEC when it still had dirt floors...
    • OFPEC
Re: Scope of variables in switch statement
« Reply #6 on: 09 Dec 2008, 03:42:30 »
@ Planck
Thanks! It's been a while. ;)

@ hoz
That's good to know, as well as good practice. Just annoying in some scripts, when you have 20 variables, just for one particle source. :P

@ Ext3rmin4tor
That's interesting. I suppose when I was taught C-like languages in college, we would never use a variable unless it was initialized before usage. SOPs for our code were to initialize any variable at the start of a class or function. So I never had to test this theory... I didn't realize you can declare a code block as a function in ArmA. That can pose extremely helpful! Thanks for the information.

[EDIT]
Ext3rmin4tor, I was just curious, and when I tried to compile a short console app in VS2008 using C++, the complier flagged an error of "error C2360: initialization of 'y' is skipped by 'case' label" when I tried to declare a variable local to a switch control structure. I didn't attempt to initialize a variable in a while or for control struct. because I would have redefined a variable using either method on the second iteration of each. I don't see how it's possible to declare a variable local to a control structure, at least in C++. Could you please explain?
« Last Edit: 09 Dec 2008, 04:41:17 by Tyger »
"People sleep soundly at night only because rough men stand ready to do violence on their behalf." - George Orwell

MSG Mike Everret - We Will Never Forget - '75-'08

Offline Ext3rmin4tor

  • Members
  • *
Re: Scope of variables in switch statement
« Reply #7 on: 09 Dec 2008, 12:59:24 »
Remember when using local function that they behave like a normal function. If you use the "call" command to run the function, the function will run synchronously to the script, i.e. the script will stop until the function returns its value. This is the ONLY way to have access to the returned value of a function but this means also that a function which has a high running time will make the game lag so in this case you need to do some optimization, although you don't usually use complex algorithms in Arma scripts. Instead you can use the "spawn" command to run a function asynchronously to the script, i.e. the function will run alongside the script (it doesn't stop it), but you can't access the returning value of the function. This can look stupid at a first look but it's the only way to have a function returning the correct value, since if another script can run alongside the function it may modify critical values the function requires and it won't return the correct value.

OT:
Maybe I know why you're a little confused about variable initialization in C-like languages. The class variables (called memeber variables) must be initialized with a constructor because they are like an object "feature": without that feature the object has no meaning. The variables used in functions are just temporary variables, the only important value is the one you return at the end, the others are just means to obtain the final value.

ANSWERING THE SWITCH QUESTION... (sorry I hadn't noticed your last question  :D):

In switch block you must declare variables before the block itself. It's a thing I've never understood completely. The only explanation I can give you is that since the "cases" of the switch block are not executed in an exclusive way (that is it's not sure that JUST one of the cases are executed, in fact if you want to execute just one of the cases you must put a "break" statement at the end of each case, it's not like in ArmA that only one case is executed) the compiler can't know in advance if it will require the variable you declared in the other case block so it casts the error because it might need the same variable in another block. But I say again: I've never understood this feature, the basic rule is that when you're using a switch block you must declare all the variables before the block itself. This is not necessary when using a sequence of "else if" like this:

Code: [Select]

if (cond1)
{
// code
}
else if (cond 2)
{
//code
}
.
.
.
else if (cond n)
{
//code
}


which is equivalent to the switch block. In Arma you can't use this method because the rule of C-like language, which says that if a control structures has at most one statement you don't have to put curly brackets, doesn't apply. The only way to build manually a switch block is to use nested if-blocks inside an else block but this becomes very hard (and this is the reason why you should always use switch block for multiple decisions in ArmA).

« Last Edit: 09 Dec 2008, 13:17:34 by Ext3rmin4tor »
How can you shoot women and children?
Easy! Ya' just don't lead'em so much! Ain't war hell?!!

Offline Tyger

  • Former Staff
  • ****
  • I was at OFPEC when it still had dirt floors...
    • OFPEC
Re: Scope of variables in switch statement
« Reply #8 on: 09 Dec 2008, 13:32:08 »
This is good stuff! So when you run a script asynchronously, you said you can not access the returning value of the function. In order to utilize the function then, does that mean your only option is to return the function to a global variable in order to access it?

Ah, this makes sense to me now. So the only variables that basically "count" are object members and the return values of functions.

That's an odd behavior, but i suppose it logically makes sense then. Thanks for the info on that. You're just a wealth of information. :) [EDIT] Ah, got it. A little OT but still relevant.
Code: [Select]
#include <iostream>

using namespace std;

int main()
{
     int x = 5;
     cout << "Local to main: " << x << endl;

     {
          cout << "Test block: " << x << endl;
          int x = 10;
          cout << "Local to block: " << x << endl;
     }
     cout << "Back to main: " << x << endl;
     return 0;
}
This of course returns 5, 5, 10, and then 5 again. That's really cool - I wish they had covered that in my CET 300s courses. :P
« Last Edit: 09 Dec 2008, 13:46:46 by Tyger »
"People sleep soundly at night only because rough men stand ready to do violence on their behalf." - George Orwell

MSG Mike Everret - We Will Never Forget - '75-'08

Offline Wolfrug

  • Addons Depot
  • Former Staff
  • ****
  • Official OFPEC Old Timer
Re: Scope of variables in switch statement
« Reply #9 on: 09 Dec 2008, 17:04:46 »
I actually didn't know about Call working the way it did until it screwed up a script of mine (er, well, I hadn't used private on the local variables in the called script, and since I'm unimaginative in coming up with variable names, the local vars in my parent script kept getting overwritten by the ones in the called script).

Basically the way I see it now is that:

Code: [Select]
//your script
_x = 0;
_x = _x + 1;
_number = _x call MathAlgorithm;
_y = _x + _number;

is the -exact equivalent- of:

Code: [Select]
//your script sans call
_x = 0;
_x = _x + 1;

//math script just a part of the parent script
_this1 = _x;
_this1 = _this + 5;
//assign output variable; in a called script this would just be the last variable left afloat at the end of the script
_number = _this1;

_y = _x + _number;

Or, in other words: the called script is more or less just copy-pasted into the middle of the parent script, inheriting all local variables and stopping the script until it's finished!

Anyway...teaches you to use private properly >__<

Wolfrug out.
"When 900 years YOU reach, look as good you will not!"

Offline Ext3rmin4tor

  • Members
  • *
Re: Scope of variables in switch statement
« Reply #10 on: 09 Dec 2008, 17:55:56 »
This is good stuff! So when you run a script asynchronously, you said you can not access the returning value of the function. In order to utilize the function then, does that mean your only option is to return the function to a global variable in order to access it?

Ah, this makes sense to me now. So the only variables that basically "count" are object members and the return values of functions.

That's an odd behavior, but i suppose it logically makes sense then. Thanks for the info on that. You're just a wealth of information. :) [EDIT] Ah, got it. A little OT but still relevant.
Code: [Select]
#include <iostream>

using namespace std;

int main()
{
     int x = 5;
     cout << "Local to main: " << x << endl;

     {
          cout << "Test block: " << x << endl;
          int x = 10;
          cout << "Local to block: " << x << endl;
     }
     cout << "Back to main: " << x << endl;
     return 0;
}
This of course returns 5, 5, 10, and then 5 again. That's really cool - I wish they had covered that in my CET 300s courses. :P

To store the returning value of a function you can use both a global variable and a local variable. The syntax is the following:

_myVariable = [arguments] call compile preprocessFile myFunction.sqf

the preprocessFile command enables the use of C++ preprocessor commands (like comments with // and /*, or #define statements), the compile command compiles the file and call executes the code returned by the compile command.

To properly build a function (that is a script returning a value) you MUST use the SQF syntax and the last line of the script is the returned value and it is not followed by ";" . For example this function computes the sum of two numbers

Code: [Select]

_num1 = _this select 0;
_num2 = _this select 1;

_res = _num1 + _num2


Remember that the last line can be an expression or a simple variable. If there are code blocks executed in an exclusive way like the if-then-else then you can put a returning value for each block (since one of them is never executed in every instance of the script). For example this script returns the maximum between two values

Code: [Select]

_val1 = _this select 0;
_val2 = _this select 1;

if (_val1 > _val2) then
{
       _val1
}
else
{
       _val2
};


Note that there are two returned lines but it is correct because just one of them is executed. You can do the same for the other controls structures but remember that there must always be onnly one returned value.

The spawn command syntax is the same of the call command except that you can't access the value of the function. This is because the spawn command already returns the "script handler", that is a sort of script ID you can use to synchronize scripts with the command "scriptDone". The code is:

[arguments] spawn compile preprocessFile "myFunction.sqf"

or

_scriptHandler = [arguments] spawn compile preprocessFile "myFunction.sqf"

NOTE: If you use call or spawn for a function local to the script, i.e. defined with a code block variable, you don't to have to use "compile" and "preprocessFile" because the variable already contains a code block and not a text file which must be compiled first.

C++ OT:

Yeah, basically variables that counts outside a context (or a scope) are function returned values and object member variables. The last one are different because you normally declare them as "private" so the user can't access them but with the class public functions. But the idea is that.

Nevertheless there's a difference between memory automatic allocation and dynamic allocation. The dynamic allocated variables are declared with the "new" instance and exists until you explicitly delete them with the "delete" instance. Dynamic allocated variables are used for example to define arrays whith a custom size, that is you don't to have to use a constant value to specify their size but you can use a variable. Usually an automatic array (the one with the size specified by a constand value) are declared like this:

int myArray[30]

if you want the size of the array to be a custom input value for example you must declare a dynamic array like this>

int size;
cin >> size;
int *myArray = new int[size];

where myArray is an integer pointer.

This is just to make you understand that for dynamic variables the scope rules do not apply. The array will exist until the program ends or you delete it with the command:

delete[] myArray;
« Last Edit: 10 Dec 2008, 11:39:00 by Ext3rmin4tor »
How can you shoot women and children?
Easy! Ya' just don't lead'em so much! Ain't war hell?!!

Offline i0n0s

  • Former Staff
  • ****
Re: Scope of variables in switch statement
« Reply #11 on: 09 Dec 2008, 18:09:46 »
_myVariable = [arguments] call compile preprocessFile myFunction.sqf
Spooner will kill you for this  ;)
Never ever use preprocessFile, instead use preprocessFileLineNumbers since it provides debug informations.

Offline Ext3rmin4tor

  • Members
  • *
Re: Scope of variables in switch statement
« Reply #12 on: 09 Dec 2008, 18:12:59 »
My debugger is my brain  :D . Anyway where are debug infos stored?
« Last Edit: 09 Dec 2008, 18:16:50 by Ext3rmin4tor »
How can you shoot women and children?
Easy! Ya' just don't lead'em so much! Ain't war hell?!!

Offline i0n0s

  • Former Staff
  • ****
Re: Scope of variables in switch statement
« Reply #13 on: 09 Dec 2008, 19:55:45 »
When you have a script error, ArmA will show the line number of the lines where the error occures. Really helps when debugging large scripts.

Offline Ext3rmin4tor

  • Members
  • *
Re: Scope of variables in switch statement
« Reply #14 on: 09 Dec 2008, 23:14:21 »
It does that also with PeprocessFile
How can you shoot women and children?
Easy! Ya' just don't lead'em so much! Ain't war hell?!!