« New to ArmA 2: Threads | Changelog 26/09/2009 » |
The three ways to execute a script
ArmA (II) has three ways to execute a script:
exec(VM), spawn and call.
execVM is the direct method. It takes a path to a file as parameter and loads and execute this file. It returns a script handle which can be used to terminate the script or check if it is finished (scriptDone).
Those shows us another detail of execVM: It won't get executed instant, so the calling script still is active.
...
spawn is similar to execVM. Instead of a string which points to the file, it requires code.
What is code?
Code is just code (), but not in a file or in a variable. Let's take a look at this snippet from Kronzky's String Functions Library:
Code:
KRON_StrUpper = { | |
private["_in","_out"]; | |
_in=_this select 0; | |
_out=toUpper(_in); | |
_out | |
}; |
Line two till five are normal code, but they are enclosed by braces. So the variable KRON_StrUpper will contain the code.
This is not the only way to declare code. Another way is to use compile:
Code:
ION_RTE_pAddObject = compile preprocessFileLineNumbers (_subpath + "\pAddObject.sqf"); |
preprocessFileLineNumbers loads a file into a string which will get compiled to a string.
And it is recommended to use preprocessFileLineNumbers instead of preprocessFile since the line numbers will get reported on an error.
Since compile uses a string, we can also modify the previous code definition:
Code:
KRON_StrUpper = compile " | |
private[""_in"",""_out""]; | |
_in=_this select 0; | |
_out=toUpper(_in); | |
_out | |
"; |
We simply put the code into a string. This one is ugly code since I used "" instead of ' inside the string, but this is for visualizing a problem: If you start using a string inside this code, then it will get ugly.
Nevertheless exists a great advantage in this method:
We can create code dynamically.
But this shall not be part of this entry.
Aside of the code, spawn works the same as execVM: It returns a script handle and the calling script remains active.
The last method is call. call requires code too, but is different from spawn: It returns the last script expression value instead of a script handle. Let's get back to the code snippet:
Code:
KRON_StrUpper = { | |
private["_in","_out"]; | |
_in=_this select 0; | |
_out=toUpper(_in); | |
_out | |
}; |
The last script value is _out, so if someone someone will call KRON_StrUpper, it will return _out:
Code:
_lower = ["AbCdEfG"] call KRON_StrUpper; |
_lower will contain "abcdefg".
Since it returns the last script expression, it requires the script to terminate. So the calling script will be suspended till the called script is done.
This doesn't hinder us from using sleep or waitUntil in the new script. At least if the context from the calling script allows the use of sleep or waitUntil.
So if we want to bypass the 3ms break, we need to use call to keep the 3ms break out of the script. And we can't use sleep or waitUntil even in the called script.
But in general we can use those without problems.
This staying in the context when using call also has a bad side effect:
Contrary to spawn and execVM, the local variables still stay valid.
Code:
_bla = "Hallo"; | |
call { | |
_bla = "Good day"; | |
}; | |
Player sideChat _bla; |
The result will be "Good day", so the called code will overwrite the local variable from the calling script.
This can get really ugly when having greater functions with a lot of local variables.
But BIS send us private. All local variables within the private statement will get exclusive for the scope of the script.
The concept of the scope should be known, at least this shall not be content of this entry too
But since the variables are now exclusive, they can't overwrite the previous values:
Code:
_bla = "Hallo"; | |
call { | |
private ["_bla"]; | |
_bla = "Good day"; | |
}; | |
Player sideChat _bla; |
The result is now "Hallo" since the _bla in the call block is exclusive and doesn't overwrite the other one.
So simply but all your local variables in the matching private statements. Helps also in code like this:
Code:
if (daytime > 14) then { | |
_message = "Good evening"; | |
} else { | |
_message = "Good morning"; | |
}; | |
Player sideChat _message; |
which uses the undefined variable _message (scopes ).
If we add a simple private, then it works without problems:
Code:
private ["_message"]; | |
if (daytime > 14) then { | |
_message = "Good evening"; | |
} else { | |
_message = "Good morning"; | |
}; | |
Player sideChat _message; |
Good morning
1 comment

/************************************/
The last script value is _out, so if someone someone will call KRON_StrUpper, it will return _out:
1.
_lower = ["AbCdEfG"] call KRON_StrUpper;
_lower will contain "abcdefg".
/************************************/
Am I misunderstanding the code in the "KRON_StrUpper" function? I'd expect to get "ABCDEFG" as a return value...?!
