diff --git a/Manual/contents/Additional_Information/Additional_Information.htm b/Manual/contents/Additional_Information/Additional_Information.htm index 5f5951c99..bf2fd1370 100644 --- a/Manual/contents/Additional_Information/Additional_Information.htm +++ b/Manual/contents/Additional_Information/Additional_Information.htm @@ -27,7 +27,6 @@
Every function has a "static struct", where its static variables are stored. You can get that struct using static_get:
-function counter() {
- static count = 0;
- return count ++;
- }
-
- repeat (10) counter();
-
- // Get static struct of counter()
- var _static_counter = static_get(counter);
-
- // Both of these read the same variable
- show_debug_message(counter.count); // 10
- show_debug_message(_static_counter.count); // 10
-
This is also true for constructor functions. Each constructor has a static struct, where its static variables and static methods are stored.
-Every struct created from the constructor accesses its static variables from that static struct.
-When you use constructor inheritance, those constructors form a "static chain" - a chain of static structs where each child links to its parent.
-For example, let's say you have a constructor item, and a constructor potion which is a child of item:
-function item() constructor {}
-
- function potion() : item() constructor {}
-
- var _potion = new potion();
-
You can get the static struct of potion using static_get(potion) - this is where the static variables for potion are stored. Let's call this static_potion.
-Now, if you call static_get(static_potion), you will get the static struct for item! This is the same struct you would get from static_get(item).
-function item () constructor {}
- function potion () : item () constructor {}
-
- var _potion = new potion();
- var _static_potion = static_get(potion);
-
- show_debug_message(static_get(item) == static_get(_static_potion)); // true (1)
-
This is because item is the parent of the potion constructor, so the static struct for item is linked to the static struct for potion.
-The static structs of the top-level constructor functions, i.e. those that don't have a parent constructor, share the same parent struct. This struct is the "root" static struct, which has undefined as its parent struct:
-var _static_item = static_get(item); // the static struct of item
- var _root = static_get(_static_item); // the static struct of all top-level static structs
- var _must_be_undefined = static_get(_root); // undefined
This shared struct is the root parent struct of all structs and defines the default toString function that's called when the struct is converted to string.
-This means that you can get the full static chain of a struct as follows:
-static_chain = [];
- var _node = static_get(potion); // the static struct to start at
- while (!is_undefined(_node))
- {
- array_push(static_chain, _node);
- _node = static_get(_node);
- };
-
- array_foreach(static_chain, show_debug_message); // output the path to the root struct
-
As static variables belong to the constructor in which they're defined, it is possible to define a static variable in a child constructor with the same name as a static variable of the parent constructor. For example:
-function shape () constructor
- {
- static count = 0;
- count++;
-
- static shapes = [];
- array_push(shapes, self);
- }
- function rectangle () : shape () constructor
- {
- static count = 0;
- count++;
- }
- function square () : rectangle () constructor
- {
- static count = 0;
- count++;
- }
- function ellipse () : shape () constructor
- {
- static count = 0;
- count++;
- }
Each shape now has its own count static variable that keeps track of the number of items of that shape. Child shapes will increment the count of their parent shapes as well, as they run their parents' constructors in addition to their own.
-s1 = new shape(); // Added 1 shape
- s2 = new rectangle(); // Added 1 rectangle (and therefore also 1 shape)
- s3 = new square(); // Added 1 square (and therefore also 1 rectangle and 1 shape)
- s4 = new ellipse(); // Added 1 ellipse (and therefore also 1 shape)
-
- show_debug_message($"Number of shapes: {shape.count}"); // 4
- show_debug_message($"Number of rectangles: {rectangle.count}"); // 2
- show_debug_message($"Number of squares: {square.count}"); // 1
- show_debug_message($"Number of ellipses: {ellipse.count}"); // 1
-
Let's say you're looking for a specific variable in a struct, using the dot operator (i.e. struct.variable_name).
-If the struct contains a non-static variable with that name, the dot operator returns that variable. If it doesn't, the dot operator returns the first variable in the static chain with that name, checking the current static struct, and then traversing back the entire static chain, if needed, until a variable with that name is encountered. If the variable name cannot be found anywhere in the static chain, GameMaker will throw an error.
-For example:
-function root() constructor {
- static show = function() {
- show_debug_message("root");
- }
- }
-
- function child() : root() constructor { }
-
- function child_with_static_func() : root() constructor {
- static show = function() {
- show_debug_message("child_with_static_func");
- }
- }
-
- function child_with_func() : root() constructor {
- show = function() {
- show_debug_message("child_with_func");
- }
- }
-
- child1 = new child();
- child1.show();
-
- child2 = new child_with_static_func();
- child2.show();
-
- child3 = new child_with_func();
- child3.show();
-
The following happens in the above code:
-In certain situations you may want to access a static variable or method of the parent constructor from within the child constructor. To achieve this, you can go up the static chain and access the parent's static variable:
-function parent() constructor
- {
- static init = function() { show_debug_message("Parent Innit?"); }
- }
-
- function child() : parent() constructor
- {
- static init = function()
- {
- var _static = static_get(self);
- var _static_parent = static_get(_static);
- _static_parent.init(); // Calls the parent's init()
-
- show_debug_message("Child Innit!");
- }
- }
-
You can use is_instanceof to check if a struct belongs to the given constructor, or has the constructor as a parent.
-This is done by checking if your struct has the given constructor's static struct anywhere in its static chain.
-The function static_set is provided to let you change the static struct of a function (constructor or not). This way you can change what static variables are available to a constructor and its structs, and also change the "static chain" that a constructor belongs to.
-The recommended use-case for this function is deserialisation. If you're loading structs from JSON, those structs won't belong to any constructors, however you can change that by using static_set to "apply" a constructor to a struct, so that that struct receives its shared static variables and you can run is_instanceof to check its kind.
--
- - - -