Difference between revisions of "Function"

From Bohemia Interactive Community
Jump to navigation Jump to search
m (fix deleted spawn refs)
m
 
(28 intermediate revisions by 6 users not shown)
Line 1: Line 1:
A '''function''' is a piece of code which performs a specific task and is relatively indepent of the remaining code.
+
{{warning | The information on this page is very outdated and often misleading. The content of this page most likely will radically change in the future.}}
They often accept input parameters and sometimes return values back to the [[Script_(File)|script]] that called them.
 
  
== Introduction ==
+
A '''function''' is something defined in code which carries out an instruction or set of instructions and may or may not have inputs and outputs. The builtin functions which are provided by the various games themselves are referred to as '''commands''', and are called in a different manor to functions which are defined within [[Script_(File)|script]]s. Functions were first introduced in the [[Operation Flashpoint: Resistance Version History|OFP: Resistance]] patch.
  
Functions were first introduced in the [[Operation Flashpoint: Resistance Version History|OFP: Resistance]] patch.
+
Functions can also be used to '''reuse code'''. You can write some code once in the function and then include it in many different scripts. When the code is updated, it is updated for all scripts. When you only copy and paste the code to the other scripts, you have to update every script on any change.
 +
 
 +
== Types of function ==
 +
=== Functions-as-files ===
 +
:''See [[Function#Call|calling functions]] for how a function-as-file is called.
 +
Functions as files are functions stored within a file. These are usually used for larger and more complex functions. The code is evaluated in the same way, however, there are additional commands which must include the file before the function itself can be called.
 +
 
 +
//MyFile.sqf
 +
 +
// Code here..
 +
 
 +
=== Inline functions ===
 +
<!-- When were these introduced ? -->
 +
Inline functions are functions are technically [[code]] which is often stored within a variable or declared as a function parameter. Inline functions operate the same way as functions-as-files as both are evaluated in the same way, but the difference is that inline functions are stored within parentheses{}, whereas functions-as-files do not require these.
 +
 
 +
//InlineFunction as Variable
 +
MyVariableName ={
 +
    // Code here..
 +
};
 +
 
 +
// InlineFunction as command/function parameter
 +
_myTemporaryVariable =[[player]] [[addEventHandler]] ["killed", {[[diag_log]] "I am providing an inline function (code) to this builtin command! Hurray for science!"}];
 +
 
 +
== Anatomy of a function ==
 +
When scripting, there are two types of functions: functions-as-files and inline functions. Functions-as-files are instances where the a whole file itself is used to house a function, whereas inline functions are either contained within a variable or as a parameter of a function. Some built-in functions require functions-as-files, whereas most will support both.
 +
 
 +
=== Parameters ===
 +
Parameters for functions are available to the function via the [[Magic Variables|magic variable]] [[_this]]. Declaration of parameters can be done using the [[params]] command. Common practice for defining parameters is done via the use of [[private]] variables and defined variables.
 +
 
 +
//MyCode.sqf
 +
params ["_parameterOne", "_parameterTwo"];
 +
 
 +
//Inline Function
 +
myInlineFunction ={
 +
    params ["_parameterOne", "_parameterTwo"];
 +
};
 +
 
 +
Parameters passed to functions are passed '''before''' the function, rather than after (such as the mathematical or c-like syntax ''f(x)'').
 +
 
 +
//Array variable as parameter
 +
_myTempParams = [_parameterOne, _parameterTwo];
 +
_myTempVariableTwo = _myTempParams call myInlineFunction;
 +
 
 +
//Array as parameter
 +
_myTempVariable = [_parameterOne,_parameterTwo] call myInlineFunction;
 +
 
 +
=== Return Values ===
 +
The value of the last executed statement in a function is returned to the calling instance.
 +
 
 +
my_fnc = {
 +
    [[if]] (_this > 0) [[exitWith]] {
 +
        _this + 1
 +
    };
 +
    _this - 1
 +
};
 +
 +
[[hint]] [[str]] (5 [[call]] my_fnc); //6
 +
[[hint]] [[str]] (-5 [[call]] my_fnc); //-6
 +
 
 +
In the first example "_this + 1" is the last executed statement in my_fnc, in the second example it is "_this - 1". Traditionally the returning statement is written without ";" after it. Have it or don't have it, it is up to you, doesn't make a blind bit of difference:
  
== Usage ==
+
my_fnc = {
 +
    a = 1;
 +
    b = 2;
 +
    c = a + b;
 +
    c //<- fine
 +
};
 +
 +
my_fnc = {
 +
    a = 1;
 +
    b = 2;
 +
    c = a + b;
 +
    c; //<- also fine
 +
};
  
Functions should be used for any processes where the '''result''' or '''calculation''' done in the function is important. This result or calculation should be made in the '''least time possible'''. They are unlike [[Script (File)|scripts]], where ''timing'' is important.
+
More examples:
 +
//myCode.sqf
 +
private _myName = _this select 0;
 +
 +
private _returnMe = "FAIL";
 +
 +
if (_myName == "Test") then {
 +
    _returnMe = "PASS";
 +
};
 +
_returnMe
  
Functions can also be used to '''reuse code'''. You can write some code once in the function and then include it in many different scripts. When the code is updated, it is updated for all scripts. When you only copy and paste the code to the other scripts, you have to update every script on any change.
+
//myCodeInline
 +
myCodeReturnValue ={
 +
    private _myName = _this select 0;
 +
    private _returnMe = "FAIL";
 +
 +
    if (_myName == "Kaboom") then {
 +
          _returnMe = "PASS";
 +
    };
 +
 +
    _returnMe
 +
};
 +
 +
_myCalledVariable = ["Kaboom"] call myCodeReturnValue; // "PASS"
 +
_myCalledVariableFail = ["Blah"] call myCodeReturnValue; // "FAIL"
  
== Syntax ==
+
//return.sqf
 +
STATEMENT 1;
 +
STATEMENT 2;
 +
RETURN_VALUE
  
Functions are strictly limited to [[SQF syntax]].  
+
//test.sqf
 +
value = [[call]] [[compile]] [[preprocessFile]] "return.sqf";
 +
// value is now RETURN_VALUE
 +
 +
[[call]] [[compile]] [[preprocessFile]] "return.sqf";
 +
// valid, but RETURN_VALUE is not saved anywhere
  
== Execution ==
+
=== Execution ===
  
[[Image: Function_Execution.png|frame|right||Function Execution Diagram<br/><br/>'''Executing Instance:''' [[Script (File)|script]], function or game engine]]
+
[[Image: Function_Execution.png|frame|right||Function Execution Diagram in [[Scheduler#Scheduled_Environment|scheduled environment]]<br/><br/>'''Executing Instance :''' [[Script (File)|script]], function or game engine]]
  
 
Functions can be executed from several points in the game:
 
Functions can be executed from several points in the game:
Line 27: Line 127:
 
* [[:Category:Event Handlers|Event Handlers]] in addon config files
 
* [[:Category:Event Handlers|Event Handlers]] in addon config files
  
Functions are first loaded as [[String]] from a file via [[preprocessFile]] or [[loadFile]]. They are then executed via the [[call]] or [[spawn]] command. Since Armed Assault the loaded [[String]] needs to be [[compile|compiled]] in order to convert it to [[Code]], which is requried for [[call]] or [[spawn]].
+
Functions are first loaded as [[String]] from a file via [[preprocessFile]] or [[loadFile]]. They are then executed via the [[call]] or [[spawn]] command. Since Armed Assault the loaded [[String]] needs to be [[compile|compiled]] in order to convert it to [[Code]], which is required for [[call]] or [[spawn]].
  
=== Call ===
+
==== Call ====
  
 
Example (Operation Flashpoint):
 
Example (Operation Flashpoint):
Line 51: Line 151:
 
'''Note:''' You can still use the special variables and commands of [[Script (File)|scripts]] in functions (Armed Assault only)!
 
'''Note:''' You can still use the special variables and commands of [[Script (File)|scripts]] in functions (Armed Assault only)!
  
=== Spawn ===
+
==== Spawn ====
  
Functions may also be executed using [[spawn_args|spawn]], but then the function result is not accessible, making it behave more like a procedure. Spawned functions will run asynchronously or ''alongside'' the executing instance. This helps prevent large CPU intensive functions from seizing up the game.
+
Functions may also be executed using [[spawn]], but then the function result is not accessible, making it behave more like a procedure. Spawned functions will run asynchronously or ''alongside'' the executing instance. This helps prevent large CPU intensive functions from seizing up the game.
  
 
Example (Armed Assault):
 
Example (Armed Assault):
Line 60: Line 160:
 
  myFunction2 = [[compile]] [[preprocessFile]] "myFunction2.sqf";
 
  myFunction2 = [[compile]] [[preprocessFile]] "myFunction2.sqf";
 
   
 
   
  [[spawn]] myFunction1;
+
  _param [[spawn]] myFunction1;
 
  [1, 2] [[spawn]] myFunction2;
 
  [1, 2] [[spawn]] myFunction2;
 
== Limitations ==
 
 
While loops used in SQS scripts (or in functions called by them) have a limitation of 10,000 loops before they are forced to exit by the game engine in order to maintain some level of stability. However, this limitation can be overcome using a 'for' loop.
 
 
== Return Value ==
 
 
The '''last [[expression]] given''' in a function is returned to the calling instance. Note that there ''must not'' be a semicolon after this value.
 
 
return.sqf
 
STATEMENT 1;
 
STATEMENT 2;
 
RETURN_VALUE
 
 
test.sqf
 
value = [[call]] [[compile]] [[preprocessFile]] "return.sqf";
 
// value is now RETURN_VALUE
 
 
[[call]] [[compile]] [[preprocessFile]] "return.sqf";
 
// valid, but RETURN_VALUE is not saved anywhere
 
  
 
== Examples ==
 
== Examples ==
Line 90: Line 170:
  
 
max.sqf
 
max.sqf
  [[comment]] "Return maximum of first and second argument";
+
  //"Return maximum of first and second argument";
  [[private variableNameList|private]] ["_a","_b"];
+
  [[params]] ["_a", "_b"];
  _a = _this [[select]] 0;
+
  [_b, _a] [[select]] (_a > _b)
  _b = _this [[select]] 1;
+
 
[[if]] (_a>_b) [[then]] {_a} [[else]] {_b}
+
alternative max.sqf (big boys code :))
 +
  (_this [[select]] 0) [[max]] (_this [[select]] 1)
  
 
executing script:
 
executing script:
Line 100: Line 181:
 
  maxValue = [3,5] [[call]] fMax;
 
  maxValue = [3,5] [[call]] fMax;
 
   
 
   
  // maxValue is now 5
+
  //maxValue is now 5
  
 
=== Example 2: infantrySafe.sqf ===
 
=== Example 2: infantrySafe.sqf ===
Line 106: Line 187:
 
In this example the function returns no value and switches all units to safe mode.
 
In this example the function returns no value and switches all units to safe mode.
  
  [[comment]] "Switch all infantry units to safe mode";
+
  //"Switch all infantry units to safe mode";
 
  {
 
  {
     [[if]] ([[vehicle]] _x == _x) [[then]]
+
     [[if]] ([[vehicle]] _x == _x) [[then]] {
    {
 
 
         _x [[setBehaviour]] "safe"
 
         _x [[setBehaviour]] "safe"
 
     }
 
     }
Line 118: Line 198:
 
An inline-function can be created in any script:
 
An inline-function can be created in any script:
  
  FNC_sayhello = {[[hint]] [[format]]["hello %1",_this]};
+
  FNC_sayhello = {[[hint]] [[format]] ["hello %1", _this]};
  
 
This function can then be called (in other scripts, functions, unit's init lines, trigger activation fields, etc.) via:
 
This function can then be called (in other scripts, functions, unit's init lines, trigger activation fields, etc.) via:
Line 124: Line 204:
 
  [[name]] [[player]] [[call]] FNC_sayhello
 
  [[name]] [[player]] [[call]] FNC_sayhello
  
Notice that there are '''no''' brackets around the functions arguments which precede the call command.<br>In case the function doesn't require any arguments you can just call the function.
+
In case the function doesn't require any arguments you can just call the function.
  
 
  [[call]] FNC_helloall
 
  [[call]] FNC_helloall

Latest revision as of 23:15, 15 June 2017

The information on this page is very outdated and often misleading. The content of this page most likely will radically change in the future.

A function is something defined in code which carries out an instruction or set of instructions and may or may not have inputs and outputs. The builtin functions which are provided by the various games themselves are referred to as commands, and are called in a different manor to functions which are defined within scripts. Functions were first introduced in the OFP: Resistance patch.

Functions can also be used to reuse code. You can write some code once in the function and then include it in many different scripts. When the code is updated, it is updated for all scripts. When you only copy and paste the code to the other scripts, you have to update every script on any change.

Types of function

Functions-as-files

See calling functions for how a function-as-file is called.

Functions as files are functions stored within a file. These are usually used for larger and more complex functions. The code is evaluated in the same way, however, there are additional commands which must include the file before the function itself can be called.

//MyFile.sqf

// Code here.. 

Inline functions

Inline functions are functions are technically code which is often stored within a variable or declared as a function parameter. Inline functions operate the same way as functions-as-files as both are evaluated in the same way, but the difference is that inline functions are stored within parentheses{}, whereas functions-as-files do not require these.

//InlineFunction as Variable
MyVariableName ={
   // Code here..
};
// InlineFunction as command/function parameter
_myTemporaryVariable =player addEventHandler ["killed", {diag_log "I am providing an inline function (code) to this builtin command! Hurray for science!"}];

Anatomy of a function

When scripting, there are two types of functions: functions-as-files and inline functions. Functions-as-files are instances where the a whole file itself is used to house a function, whereas inline functions are either contained within a variable or as a parameter of a function. Some built-in functions require functions-as-files, whereas most will support both.

Parameters

Parameters for functions are available to the function via the magic variable _this. Declaration of parameters can be done using the params command. Common practice for defining parameters is done via the use of private variables and defined variables.

//MyCode.sqf
params ["_parameterOne", "_parameterTwo"];
//Inline Function
myInlineFunction ={
    params ["_parameterOne", "_parameterTwo"];
};

Parameters passed to functions are passed before the function, rather than after (such as the mathematical or c-like syntax f(x)).

//Array variable as parameter
_myTempParams = [_parameterOne, _parameterTwo];
_myTempVariableTwo = _myTempParams call myInlineFunction;
//Array as parameter
_myTempVariable = [_parameterOne,_parameterTwo] call myInlineFunction;

Return Values

The value of the last executed statement in a function is returned to the calling instance.

my_fnc = {
    if (_this > 0) exitWith {
        _this + 1
    };
    _this - 1
};

hint str (5 call my_fnc); //6
hint str (-5 call my_fnc); //-6

In the first example "_this + 1" is the last executed statement in my_fnc, in the second example it is "_this - 1". Traditionally the returning statement is written without ";" after it. Have it or don't have it, it is up to you, doesn't make a blind bit of difference:

my_fnc = {
    a = 1;
    b = 2;
    c = a + b;
    c //<- fine
};

my_fnc = {
    a = 1;
    b = 2;
    c = a + b;
    c; //<- also fine
};

More examples:

//myCode.sqf
private _myName = _this select 0;

private _returnMe = "FAIL";

if (_myName == "Test") then {
    _returnMe = "PASS";
};
_returnMe
//myCodeInline
myCodeReturnValue ={
    private _myName = _this select 0;
    private _returnMe = "FAIL";

    if (_myName == "Kaboom") then {
         _returnMe = "PASS";
    };

    _returnMe
};

_myCalledVariable = ["Kaboom"] call myCodeReturnValue; // "PASS"
_myCalledVariableFail = ["Blah"] call myCodeReturnValue; // "FAIL"
//return.sqf
STATEMENT 1;
STATEMENT 2;
RETURN_VALUE
//test.sqf
value = call compile preprocessFile "return.sqf";
// value is now RETURN_VALUE

call compile preprocessFile "return.sqf";
// valid, but RETURN_VALUE is not saved anywhere

Execution

Function Execution Diagram in scheduled environment

Executing Instance : script, function or game engine

Functions can be executed from several points in the game:

Functions are first loaded as String from a file via preprocessFile or loadFile. They are then executed via the call or spawn command. Since Armed Assault the loaded String needs to be compiled in order to convert it to Code, which is required for call or spawn.

Call

Example (Operation Flashpoint):

myFunction1 = loadFile "myFunction1.sqf";
myFunction2 = preprocessFile "myFunction2.sqf";

call myFunction1;
[1, 2] call myFunction2;

Example (Armed Assault):

myFunction1 = compile loadFile "myFunction1.sqf";
myFunction2 = compile preprocessFile "myFunction2.sqf";

_result1 = call myFunction1;
_result2 = [1, 2] call myFunction2;

Functions executed using call are run within the executing instance, which waits for the result of the function. Unlike scripts, functions halt all other game engine processes until the function has completed its instructions. This means functions run faster than scripts, and the result of functions is immediate and unambiguous. It can also mean that if a function takes too long to run it will have an adverse effect on game play - large functions or CPU intensive functions can cause the game to seize up until it completes. When creating a functions you want the function to be short and sweet to achieve the best results.

Note: You can still use the special variables and commands of scripts in functions (Armed Assault only)!

Spawn

Functions may also be executed using spawn, but then the function result is not accessible, making it behave more like a procedure. Spawned functions will run asynchronously or alongside the executing instance. This helps prevent large CPU intensive functions from seizing up the game.

Example (Armed Assault):

myFunction1 = compile loadFile "myFunction1.sqf";
myFunction2 = compile preprocessFile "myFunction2.sqf";

_param spawn myFunction1;
[1, 2] spawn myFunction2;

Examples

Example 1: max.sqf

In this example the function returns maximum of first and second argument.

max.sqf

//"Return maximum of first and second argument";
params ["_a", "_b"];
[_b, _a] select (_a > _b)

alternative max.sqf (big boys code :))

(_this select 0) max (_this select 1)

executing script:

fMax = compile preprocessFile "max.sqf";
maxValue = [3,5] call fMax;

//maxValue is now 5

Example 2: infantrySafe.sqf

In this example the function returns no value and switches all units to safe mode.

//"Switch all infantry units to safe mode";
{
    if (vehicle _x == _x) then  {
        _x setBehaviour "safe"
    }
} forEach _this

Example 3: Inline Function

An inline-function can be created in any script:

FNC_sayhello = {hint format ["hello %1", _this]};

This function can then be called (in other scripts, functions, unit's init lines, trigger activation fields, etc.) via:

name player call FNC_sayhello

In case the function doesn't require any arguments you can just call the function.

call FNC_helloall

See also