A scope is a portion of code that exists between opening { and closing bracket }. In case of a separate script file, the scope would be the beginning and the end of the script file. Scopes can also exist within other scopes. Think of a partitioned space like a bedroom or a kitchen inside a house. A house would be the main scope. A kitchen inside would then be another scope within the main scope. To enter the kitchen you have to enter the house first and when you exit the kitchen you end up back in the house, unless you exit through a kitchen window :) . There are commands that would do exactly that and I will talk about it later on.

But first you need a door to enter. A scope on its own {… some code …} will not get its code executed, though it will have it compiled. So in order to make use of the code you need to enter this scope somehow. The simplest way is call command:

scopeName "outside"; call { scopeName "house"; call { scopeName "kitchen"; }; call { scopeName "bedroom"; }; };

There are many other ArmA commands that will make you enter scopes. spawn {}; if () then {} else {}; while {} do {}; {} forEach, etc. As you have noticed I used scopeName command to define each scope. The scopes are exited automatically when the end of scope reached. But if you want to exit the kitchen through a window, i.e. exit scopes before they reach the end, you might need the scopeName command in combination with breakOut or breakTo commands.

Both commands need to know the scope name. This scope name is either the name of the scope the command is executed in (in case of breakOut) or the name of any of the parent scopes. This is important. The scope name you indicate cannot be that of unrelated scope or of a child scope. Both commands look up and backwards to find required scope.

This means that if you are in the “bedroom” you can breakOut of “bedroom”, “house” or “outside” or breakTo “house” or “outside”. You cannot reference “kitchen” as it is not a parent of the “bedroom”. If you are in the “house” you can only breakOut of the “house” or “outside” or breakTo “outside”. You cannot reference any of the “house” children, i.e. “kitchen” or “bedroom”.

scopeName "outside"; call { scopeName "house"; call { scopeName "kitchen"; breakTo "outside"; }; call { scopeName "bedroom"; }; };

The script above will exit from the “kitchen” (through a window :) ) to the “outside”, while the script below will land you back in the “house”:

scopeName "outside"; call { scopeName "house"; call { scopeName "kitchen"; breakOut "kitchen"; }; call { scopeName "bedroom"; }; };

Another useful command for breaking out of scopes and which does not require scopeName is if exitWith construct. This command will exit current scope and current scope only. Don’t get confused by some of the information you can find on BIS wiki. There is no mystery to this command, it does what it says on the tin.

scopeName "outside"; call { scopeName "house"; call { scopeName "kitchen"; }; call { scopeName "bedroom"; if true exitWith {}; }; };

The code above will exit the “bedroom” and only the “bedroom”. So why the confusion? It seems the confusion comes from people trying foolishly to end some special loops with scope exiting commands.

While it works alright with normal loops, loops that are called by the engine every frame, such as onEachFrame or waitUntil, will understandably fail to terminate. All three commands will exit the scopes as they should, but the code inside those special loops will get executed again on the next frame, duh. If you want those loops to get terminated when you exit their scope, this is how you do it:

onEachFrame { if true exitWith {onEachFrame{}}; }; waitUntil { if true exitWith {true}; };

You also have to pay attention where and how you define your private variables when you have scopes. If you define your variable in the “house” it will be known in both “kitchen” and “bedroom” but not “outside”. I have already talked about the private variables and scopes before, you just have to remember that child scopes can inherit parent private variables but not vice versa.

_parentVar = 123; call { hint str isNil "_parentVar"; //false _childVar = 456; }; if true then { hint str isNil "_parentVar"; //false _childVar = 456; }; _null = [] spawn { hint str isNil "_parentVar"; //true _childVar = 456; }; hint str isNil "_childVar"; //true

Now it’s time to put our newly gained knowledge of scopes to good use. Remember switch do command? It is a nice command when you want to keep your code neat instead of creating monstrous if then structures, but it is a tad bit slow, which is kinda odd as everywhere else switches are lightning fast. Anyway:

private "_num2str"; _num = 0; switch _num do { case 0: {_num2str = "0"}; case 1: {_num2str = "1"}; case 2: {_num2str = "2"}; default {_num2str = "N/A"}; };

Can we keep the speed and have the tidiness of the switch? Yes we can!

private "_num2str"; _num = 0; call { if (_num == 0) exitWith {_num2str = "0"}; if (_num == 1) exitWith {_num2str = "1"}; if (_num == 2) exitWith {_num2str = "2"}; _num2str = "N/A"; };

The code above will also give you case insensitive string comparison while switch is actually case sensitive.

Enjoy,
KK