Enforce Script Syntax – DayZ
Lou Montana (talk | contribs) m (Some wiki formatting) |
Lou Montana (talk | contribs) (Add Arma Reforger note, Add <enforce> usage) |
||
Line 1: | Line 1: | ||
{{TOC|side}} | {{TOC|side}} | ||
'''Enforce Script''' is the language that is used by the [[ | '''Enforce Script''' is the language that is used by the [[Enfusion]] engine first introduced in [[:Category:DayZ|DayZ]] Standalone. It is a Object-Oriented Scripting Language (OOP) that works with objects and classes and is similar to C# programming language. | ||
{{Feature|armaR|For {{armaR}}, see {{GameCategory|armaR|Modding|Tutorials|Scripting|link=y|text={{armaR}} Scripting Tutorials}} starting with [[Arma Reforger:From SQF to Enforce Script]].}} | |||
Line 10: | Line 13: | ||
Scope example | Scope example | ||
< | <enforce> | ||
void Hello() | void Hello() | ||
{ | { | ||
Line 20: | Line 23: | ||
int x = 23; // Different x not related to the first one | int x = 23; // Different x not related to the first one | ||
} | } | ||
</ | </enforce> | ||
Nested scope | Nested scope | ||
< | <enforce> | ||
void World() | void World() | ||
{ | { | ||
Line 34: | Line 37: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
Scope statements | Scope statements | ||
< | <enforce> | ||
void Hello() | void Hello() | ||
{ | { | ||
Line 51: | Line 54: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
=== Program structure === | === Program structure === | ||
Line 57: | Line 60: | ||
Enforce Script consists of classes and functions. All code must be declared inside a function. | Enforce Script consists of classes and functions. All code must be declared inside a function. | ||
< | <enforce> | ||
class MyClass | class MyClass | ||
{ | { | ||
Line 72: | Line 75: | ||
Print("Hello World"); // this code will be never executed, and should be caught by compiler as unexpected statement | Print("Hello World"); // this code will be never executed, and should be caught by compiler as unexpected statement | ||
</ | </enforce> | ||
=== Variables === | === Variables === | ||
Variables are defined by type and name. | Variables are defined by type and name. | ||
< | <enforce> | ||
void Test() | void Test() | ||
{ | { | ||
Line 89: | Line 92: | ||
int b = 9; | int b = 9; | ||
} | } | ||
</ | </enforce> | ||
=== Functions === | === Functions === | ||
Line 101: | Line 104: | ||
* Enforce Script supports default parameter | * Enforce Script supports default parameter | ||
< | <enforce> | ||
void MethodA() // function with no parameters and no return value | void MethodA() // function with no parameters and no return value | ||
{ | { | ||
Line 160: | Line 163: | ||
void PrintCount(TStringArray stringArray) // function with one "TStringArray" object parameter which returns no value | void PrintCount(TStringArray stringArray) // function with one "TStringArray" object parameter which returns no value | ||
{ | { | ||
if (!stringArray) | if (!stringArray) // check if stringArray is not null | ||
return; | |||
int count = stringArray.Count(); | int count = stringArray.Count(); | ||
Print(count); | Print(count); | ||
} | } | ||
</ | </enforce> | ||
=== Comments === | === Comments === | ||
< | <enforce> | ||
/* | /* | ||
Multi | Multi | ||
Line 180: | Line 184: | ||
Print("Hello"); // single line comment | Print("Hello"); // single line comment | ||
} | } | ||
</ | </enforce> | ||
=== Constants === | === Constants === | ||
Line 186: | Line 190: | ||
Constants are like variables but read only. They are declared by const keyword. | Constants are like variables but read only. They are declared by const keyword. | ||
< | <enforce> | ||
const int MONTHS_COUNT = 12; | const int MONTHS_COUNT = 12; | ||
Line 194: | Line 198: | ||
MONTHS_COUNT = 7; // err! you cannot change constant! | MONTHS_COUNT = 7; // err! you cannot change constant! | ||
} | } | ||
</ | </enforce> | ||
Line 292: | Line 296: | ||
Overriding the index operator can be achieved through the {{hl|Set}} and {{hl|Get}} methods. You can have any number of overloads as long as there is no ambiguity with the types. | Overriding the index operator can be achieved through the {{hl|Set}} and {{hl|Get}} methods. You can have any number of overloads as long as there is no ambiguity with the types. | ||
< | <enforce> | ||
class IndexOperatorTest | class IndexOperatorTest | ||
{ | { | ||
int data[3]; | |||
void Set(int _index, int _value) | void Set(int _index, int _value) | ||
Line 311: | Line 315: | ||
instance[1] = 5; | instance[1] = 5; | ||
Print(instance[1]); // prints '5' | Print(instance[1]); // prints '5' | ||
</ | </enforce> | ||
'''Note:''' If you want to assign a pre-parsed vector with < | '''Note:''' If you want to assign a pre-parsed vector with <enforce inline>instance[index] = "1 1 1"</enforce> the setter needs to accept a {{hl|string}} as {{hl|_value}} parameter and convert it explicitly using <enforce inline>_value.ToVector()</enforce> before an assignment. | ||
Line 371: | Line 375: | ||
|} | |} | ||
=== Other | === Other Keywords === | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 431: | Line 435: | ||
* Strings can contain standardized escape sequences. These are supported: \n \r \t \\ \" | * Strings can contain standardized escape sequences. These are supported: \n \r \t \\ \" | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 442: | Line 446: | ||
Print(c); // prints "Hello world!" | Print(c); // prints "Hello world!" | ||
} | } | ||
</ | </enforce> | ||
=== Vectors === | === Vectors === | ||
Line 451: | Line 455: | ||
* Vector can be initialized by three numeric values in double quotes e.g. "10 22 13" | * Vector can be initialized by three numeric values in double quotes e.g. "10 22 13" | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 463: | Line 467: | ||
Print(down); // prints <0, -1, 0> | Print(down); // prints <0, -1, 0> | ||
} | } | ||
</ | </enforce> | ||
=== Objects === | === Objects === | ||
Line 471: | Line 475: | ||
* 'autoptr' keyword before object variable declaration ensures that compiler automatically destroys the object when the scope is terminated (e.g. function call ends) | * 'autoptr' keyword before object variable declaration ensures that compiler automatically destroys the object when the scope is terminated (e.g. function call ends) | ||
< | <enforce> | ||
class MyClass | class MyClass | ||
{ | { | ||
Line 532: | Line 536: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
Example of '''this''' & '''super''': | Example of '''this''' & '''super''': | ||
< | <enforce> | ||
class AnimalClass | class AnimalClass | ||
{ | { | ||
Line 559: | Line 563: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
=== Enums === | === Enums === | ||
Line 570: | Line 574: | ||
* enum name used as type behaves like ordinary int (no enum value checking on assign) | * enum name used as type behaves like ordinary int (no enum value checking on assign) | ||
< | <enforce> | ||
enum MyEnumBase | enum MyEnumBase | ||
{ | { | ||
Line 595: | Line 599: | ||
Print(c); // prints '20' | Print(c); // prints '20' | ||
Print(MyEnum.Alfa); // prints '5' | |||
} | } | ||
</ | </enforce> | ||
=== Templates === | === Templates === | ||
Line 606: | Line 610: | ||
* Enforce Script supports any number of generic types per template class | * Enforce Script supports any number of generic types per template class | ||
< | <enforce> | ||
class Item<Class T> | class Item<Class T> | ||
{ | { | ||
Line 636: | Line 640: | ||
int_item.PrintData(); // prints "m_data = 72" | int_item.PrintData(); // prints "m_data = 72" | ||
} | } | ||
</ | </enforce> | ||
=== Arrays === | === Arrays === | ||
Line 647: | Line 651: | ||
* Elements are accessible by array access operator [ ] | * Elements are accessible by array access operator [ ] | ||
< | <enforce> | ||
void MethodA() | void MethodA() | ||
{ | { | ||
Line 677: | Line 681: | ||
int numbersArray[size]; // err! size static array cannot be declared by variable! | int numbersArray[size]; // err! size static array cannot be declared by variable! | ||
} | } | ||
</ | </enforce> | ||
==== Dynamic Arrays ==== | ==== Dynamic Arrays ==== | ||
Line 692: | Line 696: | ||
** array<vector> = TVectorArray | ** array<vector> = TVectorArray | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 712: | Line 716: | ||
Print(nameCount); // prints "nameCount = 2" | Print(nameCount); // prints "nameCount = 2" | ||
} | } | ||
</ | </enforce> | ||
=== Automatic type detection === | === Automatic type detection === | ||
Line 718: | Line 722: | ||
The variable type will be detected automatically at compile time when the keyword '''auto''' is used as placeholder. | The variable type will be detected automatically at compile time when the keyword '''auto''' is used as placeholder. | ||
< | <enforce> | ||
class MyCustomClass(){} | class MyCustomClass(){} | ||
Line 727: | Line 731: | ||
auto variableInst = new MyCustomClass(); // variableInst will be of type MyCustomClass | auto variableInst = new MyCustomClass(); // variableInst will be of type MyCustomClass | ||
} | } | ||
</ | </enforce> | ||
Line 737: | Line 741: | ||
==== If statement ==== | ==== If statement ==== | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 776: | Line 780: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
==== Switch statement ==== | ==== Switch statement ==== | ||
Switch statement supports switching by numbers, constants and strings. | Switch statement supports switching by numbers, constants and strings. | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 839: | Line 843: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
=== Iteration structures === | === Iteration structures === | ||
Line 845: | Line 849: | ||
==== For ==== | ==== For ==== | ||
The for loop consists of three parts: declaration, condition and increment. | The for loop consists of three parts: declaration, condition and increment. | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 861: | Line 865: | ||
void ListArray(TStringArray a) | void ListArray(TStringArray a) | ||
{ | { | ||
if (a == null) | if (a == null) // check if "a" is not null | ||
return; | |||
int i = 0; | int i = 0; | ||
Line 872: | Line 877: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
==== Foreach ==== | ==== Foreach ==== | ||
Simpler and more comfortable version of for loop. | Simpler and more comfortable version of for loop. | ||
< | <enforce> | ||
void TestFn() | void TestFn() | ||
{ | { | ||
Line 911: | Line 916: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
==== While ==== | ==== While ==== | ||
< | <enforce> | ||
void Method() | void Method() | ||
{ | { | ||
Line 930: | Line 935: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
Line 944: | Line 949: | ||
=== Inheritance === | === Inheritance === | ||
< | <enforce> | ||
class AnimalClass | class AnimalClass | ||
{ | { | ||
Line 997: | Line 1,002: | ||
LetAnimalMakeSound(pluto); // prints "Wof! Wof!" | LetAnimalMakeSound(pluto); // prints "Wof! Wof!" | ||
} | } | ||
</ | </enforce> | ||
=== Constructor & Destructor === | === Constructor & Destructor === | ||
Line 1,011: | Line 1,016: | ||
* When constructor doesn't have any parameters omit brackets while using 'new' operator | * When constructor doesn't have any parameters omit brackets while using 'new' operator | ||
< | <enforce> | ||
class MyClassA | class MyClassA | ||
{ | { | ||
Line 1,048: | Line 1,053: | ||
delete b; // prints "Instance of MyClassB is destroyed!" | delete b; // prints "Instance of MyClassB is destroyed!" | ||
} // here at the end of scope ARC feature automatically destroys 'a' object and it prints "Instance of MyClassA is destroyed!" | } // here at the end of scope ARC feature automatically destroys 'a' object and it prints "Instance of MyClassA is destroyed!" | ||
</ | </enforce> | ||
=== Managed class & pointer safety === | === Managed class & pointer safety === | ||
Line 1,056: | Line 1,061: | ||
* All objects available in game module should be Managed, so they should be using soft links by default (they all inherits from Managed class) | * All objects available in game module should be Managed, so they should be using soft links by default (they all inherits from Managed class) | ||
< | <enforce> | ||
// without Managed | // without Managed | ||
class A | class A | ||
Line 1,099: | Line 1,104: | ||
if (a2) a2.Hello(); // nothing happens because a2 is also NULL, thus this code will always be safe | if (a2) a2.Hello(); // nothing happens because a2 is also NULL, thus this code will always be safe | ||
} | } | ||
</ | </enforce> | ||
=== Automatic Reference Counting === | === Automatic Reference Counting === | ||
Line 1,118: | Line 1,123: | ||
* weak reference just pointing to an object, but doesn't increase reference count | * weak reference just pointing to an object, but doesn't increase reference count | ||
< | <enforce> | ||
class Parent | class Parent | ||
{ | { | ||
Line 1,138: | Line 1,143: | ||
// local variables 'a', 'b' are released (reference count is decreased by 1) | // local variables 'a', 'b' are released (reference count is decreased by 1) | ||
} | } | ||
</ | </enforce> | ||
In the code above at the end of function main, object 'a' has zero strong references thus is deleted, destructor releases m_child, and so the object 'b' also has zero strong references and it is deleted. | In the code above at the end of function main, object 'a' has zero strong references thus is deleted, destructor releases m_child, and so the object 'b' also has zero strong references and it is deleted. | ||
Line 1,158: | Line 1,163: | ||
Examples: | Examples: | ||
< | <enforce> | ||
class MyClassA | class MyClassA | ||
{ | { | ||
Line 1,258: | Line 1,263: | ||
ref MyClassA m_e[10]; | ref MyClassA m_e[10]; | ||
}; | }; | ||
</ | </enforce> | ||
Line 1,271: | Line 1,276: | ||
* When several modded classes are modding the same vanilla class, the next modded class will instead inherit of the latest modded class, which enables mod compatibility | * When several modded classes are modding the same vanilla class, the next modded class will instead inherit of the latest modded class, which enables mod compatibility | ||
< | <enforce> | ||
// original | // original | ||
class ModMe | class ModMe | ||
Line 1,306: | Line 1,311: | ||
a.Say(); // prints 'Hello modded Two' , 'Hello modded One' and 'Hello original' | a.Say(); // prints 'Hello modded Two' , 'Hello modded One' and 'Hello original' | ||
} | } | ||
</ | </enforce> | ||
=== Modded constants === | === Modded constants === | ||
Line 1,313: | Line 1,318: | ||
* Allows multiple mods to change different constants in a single class | * Allows multiple mods to change different constants in a single class | ||
< | <enforce> | ||
class BaseTest | class BaseTest | ||
{ | { | ||
Line 1,337: | Line 1,342: | ||
Print(TestConst.CONST_MOD); // 3 | Print(TestConst.CONST_MOD); // 3 | ||
} | } | ||
</ | </enforce> | ||
=== Modded private members === | === Modded private members === | ||
Line 1,343: | Line 1,348: | ||
* Even though modded class behaves similar to an inherited one, it can still access private members of the vanilla class | * Even though modded class behaves similar to an inherited one, it can still access private members of the vanilla class | ||
< | <enforce> | ||
// original | // original | ||
class VanillaClass | class VanillaClass | ||
Line 1,372: | Line 1,377: | ||
} | } | ||
} | } | ||
</ | </enforce> | ||
[[Category:Syntax]] | [[Category:Syntax]] | ||
[[Category:DayZ:Scripting]] | [[Category:DayZ:Scripting]] |
Revision as of 01:01, 3 August 2022
Enforce Script is the language that is used by the Enfusion engine first introduced in DayZ Standalone. It is a Object-Oriented Scripting Language (OOP) that works with objects and classes and is similar to C# programming language.
Basics
Code blocks
Code block is bordered by curly brackets and defines a scope. Variables defined inside scope are accessible only from inside of it.
Scope example
Nested scope
Scope statements
Program structure
Enforce Script consists of classes and functions. All code must be declared inside a function.
Variables
Variables are defined by type and name.
Functions
Functions are basic feature of Enforce Script. Function declaration consist of return value type, function name and list of parameters.
- Functions can be declared in global scope or inside class declaration
- Function parameters are fixed and typed (cannot be changed during run-time, no variadic parameters)
- Functions can be overloaded
- Keyword 'out' before parameter declaration ensures, that the parameter is passed by reference (you can pass more than one value from a function this way, can be used only in native functions)
- Enforce Script supports default parameter
Comments
Constants
Constants are like variables but read only. They are declared by const keyword.
Operators
Operator Priority: Priority of operators is similar to C language, more info.
Arithmetic Operators
Operation | Symbol |
---|---|
Add | + |
Subtract | - |
Multiply | * |
Divide | |
Modulo | % |
Assignments
Operation | Symbol |
---|---|
Assign value to variable | = |
Increment variable by value | += |
Decrement variable by value | -= |
Multiply variable by value | *= |
Divide variable by value | |
Bitwise-OR by value | |= |
Bitwise-AND by value | &= |
Left-shift variable by value | <<= |
Right-shift variable by value | >>= |
Increment variable by 1 | ++ |
Decrement variable by 1 | -- |
Relational (conditional)
Operation | Symbol |
---|---|
More than value | > |
Less than value | < |
More or equal to the value | >= |
Less or equal to the value | <= |
Equal | == |
Not equal | != |
Others
Category | Operator(s) |
---|---|
Logical | &&, || |
Bitwise | &, |, ~, ^ |
String | + |
Shift | <<, >> |
Assignment | = |
Indexing | [ ] |
Negation | ! |
Script Overriding
Index Operator
Overriding the index operator can be achieved through the Set and Get methods. You can have any number of overloads as long as there is no ambiguity with the types.
Note: If you want to assign a pre-parsed vector with instance[index] = "1 1 1" the setter needs to accept a string as _value parameter and convert it explicitly using _value.ToVector() before an assignment.
Keywords
Function/method modifiers
Keyword | Description |
---|---|
private | The method can be called only from inside of the same class method |
protected | The method can be called only from inside of class method or methods of its extended classes |
static | The method can be called without object pointer, just by className.methodName() , only static members of the same class can be accessed from inside of static method |
override | Compiler checks if is method present in base class and if method signature match |
proto | Prototyping of internal function (C++ side) |
native | Native call convention of internal function (C++ side) |
Variable modifiers
Keyword | Description |
---|---|
private | Variable can be accessed only from inside of class methods. Mutually exclusive with "protected" |
protected | Variable can be accessed only from inside of class methods or methods of its extended classes. Mutually exclusive with "private" |
static | Variable can be accessed without object pointer, using className.variable |
autoptr | Modifier for variables of class pointer type. Pointer target will be automatically destroyed upon end of variable lifetime (end of scope or deletion of class which contains it) |
proto | Prototyping of internal function (C++ side) |
ref | Variable is a strong reference |
const | Constant, cannot be modified |
out | Modifier for function parameters, variable will be changed by a function call |
inout | Modifier for function parameters, variable will be used and then changed by a function call |
Class modifiers
Keyword | Description |
---|---|
modded | Inheritance-like behaviour for modding |
Other Keywords
Keyword | Description |
---|---|
new | Create new object instance |
delete | Destroy object instance |
class | Class declaration |
extends | Class inheritence |
typedef | Type definition |
return | Terminates function & returns value (if specified) |
null | null value |
this | Address of the object, on which the member function is being called |
super | Refers to the base class for the requested variable/function |
thread | Declared before the function call, runs the function on a new thread |
Types
Primitive Types
Type name | Range | Default Value |
---|---|---|
int | from −2,147,483,648 to +2,147,483,647 | 0 |
float | from ±1.401298E−45 to ±3.402823E+38 | 0.0 |
bool | true or false | false |
string | - | "" (empty string) |
vector | see float | (0.0,0.0,0.0) |
void | - | - |
Class | - | null |
typename | - | null |
Strings
- Strings are passed by value, like primitive types
- Can be concatenated by + operator
- Strings are initialized and destroyed automatically
- Strings can contain standardized escape sequences. These are supported: \n \r \t \\ \"
Vectors
- Vectors are passed by value, like primitive types
- Vector values are accessible by [, ] operator, like static arrays
- Vectors are initialized and destroyed automatically
- Vector can be initialized by three numeric values in double quotes e.g. "10 22 13"
Objects
- Objects in enforce script are references and are passed by reference
- All member functions and variables are public by default. Use 'private' keyword to make them private
- 'autoptr' keyword before object variable declaration ensures that compiler automatically destroys the object when the scope is terminated (e.g. function call ends)
Example of this & super:
Enums
Enumerators are set of named constant identifiers.
- enums have int type
- enum item value can be assigned in definition, otherwise it is computed automatically (previous item value plus one)
- enum can inherit from another enum (item value continues from last parent item value)
- enum name used as type behaves like ordinary int (no enum value checking on assign)
Templates
Enforce Script has template feature similar to C++ Templates, which allows classes to operate with generic types.
- Generic type declaration is placed inside <, > (e.g. "class TemplateClass<class GenericType>" )operators after template class name identifier
- Enforce Script supports any number of generic types per template class
Arrays
Static Arrays
- Arrays are indexed from 0
- Arrays are passed by reference, like objects
- Static arrays are initialized and destroyed automatically
- Size of static arrays can be set only during compilation time
- Elements are accessible by array access operator [ ]
Dynamic Arrays
- Dynamic arrays support change of size at runtime by inserting/removing array items
- Dynamic arrays are provided through 'array' template class
- Dynamic arrays are passed by reference
- Dynamic Arrays are objects and therefore they must be created and destroyed like objects, so don't forget to use "autoptr" or delete operator!
- Elements are accessible by "Get" function or by array access operator [ ]
- There are already defined typedefs for primitive type arrays:
- array<string> = TStringArray
- array<float> = TFloatArray
- array<int> = TIntArray
- array<class> = TClassArray
- array<vector> = TVectorArray
Automatic type detection
The variable type will be detected automatically at compile time when the keyword auto is used as placeholder.
Control Structures
Control structures work very similar to C# or C/C++ languages.
Conditional structures
If statement
Switch statement
Switch statement supports switching by numbers, constants and strings.
Iteration structures
For
The for loop consists of three parts: declaration, condition and increment.
Foreach
Simpler and more comfortable version of for loop.
While
Object-oriented programming specifics
- All member functions and variables are public by default. You can use 'private' or 'protected' keyword to control access
- Class member functions are virtual and can be overriden by child class
- Use override keyword for overriding base class methods(to avoid accidental overriding)
- Class can inherit from one parent class using keyword 'extends'
- Objects are not initialized and destroyed automatically, use 'new' and 'delete' (or 'autoptr' feature)
- Class variables are cleared to default values upon creation
Inheritance
Constructor & Destructor
Constructor and destructor are special member functions
- Every class can have one constructor and one destructor
- Constructor is function called when object is created(by 'new') and has same name as class ( e.g. 'void ClassName()' )
- Destructor is called when object is going to be destroyed (by 'delete'/'autoptr') and has same name as class with tilde character at beginning ( e.g. 'void ~ClassName()' )
- Constructor can have initialization parameters, destructor cannot have any parameters
- Both constructor and destructor do not return any value (returns void)
- Constructor and destructor are called even when object is created or destroyed from C++
- When constructor doesn't have any parameters omit brackets while using 'new' operator
Managed class & pointer safety
- Since script does not do garbage collecting automatically, all plain pointers are considered unsafe
- All classes inherited from Managed class work soft links instead of plain pointers. Soft link is weak reference that does not keep the object alive and is zeroed upon their destruction so they are never invalid
- All objects available in game module should be Managed, so they should be using soft links by default (they all inherits from Managed class)
Automatic Reference Counting
Enforce Script has support of automatic reference counting. In a spirit of flexibility, you can choose if your class should or shouldn't be managed, by choosing to inherit from Managed class.
Simple "C++" like classes remains an option for high performance, but less secure scripts
- objects referenced by plain C pointers
- no automatic memory management, owner must delete them
For common gameplay scripts/mods/etc there are managed objects, which are
- slightly slower (due indirect weak pointer object accessing)
- internally ref-counted and automatically deleted when not needed
- objects referenced by weak pointers (pointer is always valid or NULL, never points to deleted memory etc.)
Strong and weak references
- strong reference increases reference count - holds object alive
- weak reference just pointing to an object, but doesn't increase reference count
In the code above at the end of function main, object 'a' has zero strong references thus is deleted, destructor releases m_child, and so the object 'b' also has zero strong references and it is deleted.
Usage of ref keyword
In the Enforce script by default all variables are weak references, ref keyword is marking that variable is strong reference. In some special cases, variables are strong references by default
- local variables inside functions
- function arguments
- function return value
and are released after their scope ends.
While an object is stored in at least one strong reference, it's being kept alive. When the last strong reference is destroyed or overwritten, the object is destroyed and all other (only weak refs left) references are set to NULL. When an object is deleted manually by delete command (e.g., 'delete a;'), it is deleted immediately ignoring reference count, and all references (weak and strong) are set to NULL.
Optimal usage of references in Enforce script is to have exactly one strong reference per object, placed in "owner" object who creates it. This way of usage ensures
- no cyclic references
- proper order of object destruction - object is destroyed when its "creator" is destroyed
Examples:
Modding
Modded class
Modded class is used to inject inherited class into class hierarchy without modifying other scripts, which is required for proper modding:
- Modded class behaves like class inherited from original class (you can use super to access original class)
- When modded class is declared, it will be instanced instead of original class everywhere in the script
- When several modded classes are modding the same vanilla class, the next modded class will instead inherit of the latest modded class, which enables mod compatibility
Modded constants
- Constants can be overridden on compilation by the the last loaded mod (be mindful of the mod load order)
- Allows multiple mods to change different constants in a single class
Modded private members
- Even though modded class behaves similar to an inherited one, it can still access private members of the vanilla class