Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions committed Dec 13, 2023
2 parents 7f15c0c + 04d09ec commit 7ec6995
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Static Struct</title>
<meta name="generator" content="Adobe RoboHelp 2020" />
<meta name="generator" content="Adobe RoboHelp 2022" />
<link rel="stylesheet" href="../../../assets/css/default.css" type="text/css" />
<script src="../../../assets/scripts/main_script.js" type="module"></script>
<meta name="rh-authors" content="Gurpreet S. Matharoo" />
Expand All @@ -21,7 +21,7 @@ <h1><span data-field="title" data-format="default">Static Struct</span></h1>
    return count ++;<br />
}<br />
<br />
repeat (10) counter()<br />
repeat (10) counter();<br />
<br />
// Get static struct of counter()<br />
var _static_counter = static_get(counter);<br />
Expand All @@ -32,6 +32,7 @@ <h1><span data-field="title" data-format="default">Static Struct</span></h1>
</p>
<p>This is also true for <a href="../Structs.htm#constr">constructor functions</a>. Each constructor has a static struct, where its static variables and static methods are stored.</p>
<p>Every struct created from the constructor accesses its static variables from that static struct.</p>
<div data-conref="../../../assets/snippets/Note_Warning_Static_Struct_Call_Once.hts"> </div>
<h2 id="h">Static Chain</h2>
<p>When you use constructor inheritance, those constructors form a &quot;static chain&quot; - a chain of static structs where each child links to its parent.</p>
<p>For example, let&#39;s say you have a constructor <span class="inline2">item</span>, and a constructor <span class="inline2">potion</span> which is a child of <span class="inline2">item</span>:</p>
Expand All @@ -52,6 +53,116 @@ <h2 id="h">Static Chain</h2>
show_debug_message(static_get(item) == static_get(_static_potion)); // true (1)
</p>
<p>This is because <span class="inline2">item</span> is the parent of the <span class="inline2">potion</span> constructor, so the static struct for <span class="inline2">item</span> is linked to the static struct for <span class="inline2">potion</span>.</p>
<p>The static structs of the top-level constructor functions, i.e. those that don&#39;t have a parent constructor, share the same parent struct. This struct is the &quot;root&quot; static struct, which has <span class="inline2">undefined</span> as its parent struct: </p>
<p class="code">var _static_item = static_get(item);         // the static struct of item<br />
var _root = static_get(_static_item);        // the static struct of all top-level static structs<br />
var _must_be_undefined = static_get(_root);  // undefined</p>
<p>This shared struct is the root parent struct of <em>all</em> structs and defines the default <span class="inline3_func">toString</span> function that&#39;s called when the struct is converted to string.</p>
<p>This means that you can get the full static chain of a struct as follows:</p>
<p class="code">static_chain = [];<br />
var _node = static_get(potion);                        // the static struct to start at<br />
while (!is_undefined(_node))<br />
{<br />
    array_push(static_chain, _node);<br />
    _node = static_get(_node);<br />
};<br />
<br />
array_foreach(static_chain, show_debug_message);       // output the path to the root struct
</p>
<h2>Same Variable Name in Parent &amp; Child Constructor</h2>
<p>As static variables belong to the constructor in which they&#39;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: </p>
<p class="code">function shape () constructor<br />
{<br />
    static count = 0;<br />
    count++;<br />
    <br />
    static shapes = [];<br />
    array_push(shapes, self);<br />
}<br />
function rectangle () : shape () constructor<br />
{<br />
    static count = 0;<br />
    count++;<br />
}<br />
function square () : rectangle () constructor<br />
{<br />
    static count = 0;<br />
    count++;<br />
}<br />
function ellipse () : shape () constructor<br />
{<br />
    static count = 0;<br />
    count++;<br />
}</p>
<p>Each shape now has its own <span class="inline2">count</span> static variable that keeps track of the number of items of that shape. Child shapes will increment the <span class="inline2">count</span> of their parent shapes as well, as they run their parents&#39; constructors in addition to their own.</p>
<p class="code">s1 = new shape();        // Added 1 shape<br />
s2 = new rectangle();    // Added 1 rectangle (and therefore also 1 shape)<br />
s3 = new square();       // Added 1 square (and therefore also 1 rectangle and 1 shape)<br />
s4 = new ellipse();      // Added 1 ellipse (and therefore also 1 shape)<br />
<br />
show_debug_message($&quot;Number of shapes: {shape.count}&quot;);          // 4<br />
show_debug_message($&quot;Number of rectangles: {rectangle.count}&quot;);  // 2<br />
show_debug_message($&quot;Number of squares: {square.count}&quot;);        // 1<br />
show_debug_message($&quot;Number of ellipses: {ellipse.count}&quot;);      // 1
</p>
<h2 id="h2">How the Dot Operator Looks Up a Variable Name</h2>
<p>Let&#39;s say you&#39;re looking for a specific variable in a struct, using the dot operator (i.e. <span class="inline2">struct.variable_name</span>).</p>
<p>If the struct contains a non-static variable with that name, the dot operator returns that variable. If it doesn&#39;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, <span data-keyref="GameMaker Name">GameMaker</span> will throw an error.</p>
<p>For example:</p>
<p class="code">function root() constructor {<br />
    static show = function() {<br />
        show_debug_message(&quot;root&quot;);<br />
    }<br />
}<br />
<br />
function child() : root() constructor { }<br />
<br />
function child_with_static_func() : root() constructor {<br />
    static show = function() {<br />
        show_debug_message(&quot;child_with_static_func&quot;);<br />
    }<br />
}<br />
<br />
function child_with_func() : root() constructor {<br />
    show = function() {<br />
        show_debug_message(&quot;child_with_func&quot;);<br />
    }<br />
}<br />
<br />
child1 = new child();<br />
child1.show();<br />
<br />
child2 = new child_with_static_func();<br />
child2.show();<br />
<br />
child3 = new child_with_func();<br />
child3.show();
</p>
<p>The following happens in the above code: </p>
<ul class="colour">
<li><span class="inline2">child1</span> is a <span class="inline2">child</span>, which has no <span class="inline3_func">show()</span> method of its own but inherits from <span class="inline2">root</span>. <span class="inline3_func">root.show()</span> is called and <span class="inline2">&quot;root&quot;</span> is output.</li>
<li><span class="inline2">child2</span> is a <span class="inline2">child_with_static_func</span>, which has a static <span class="inline2">show()</span> method. This method is called, which outputs <span class="inline2">&quot;child_with_static_func&quot;</span>.</li>
<li><span class="inline2">child3</span> is a <span class="inline2">child_with_func</span>, which inherits from <span class="inline2">root</span> but also has its own (non-static) <span class="inline3_func">show()</span> method. It calls its own <span class="inline3_func">show()</span> method, outputting <span class="inline2">&quot;child_with_func&quot;</span>.</li>
</ul>
<h2>Parent&#39;s Static Variable or Method</h2>
<p>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&#39;s static variable: </p>
<p class="code">function parent() constructor<br />
{<br />
    static init = function() { show_debug_message(&quot;Parent Innit?&quot;); }<br />
}<br />
<br />
function child() : parent() constructor<br />
{<br />
    static init = function()<br />
    {<br />
        var _static = static_get(self);<br />
        var _static_parent = static_get(_static);<br />
        _static_parent.init(); // Calls the parent&#39;s init()<br />
        <br />
        show_debug_message(&quot;Child Innit!&quot;);<br />
    }<br />
}
</p>
<h2>Checking Inheritance</h2>
<p>You can use <span class="inline3_func"><a data-xref="{title}" href="../../GML_Reference/Variable_Functions/is_instanceof.htm">is_instanceof</a></span> to check if a struct belongs to the given constructor, or has the constructor as a parent.</p>
<p>This is done by checking if your struct has the given constructor&#39;s static struct anywhere in its static chain.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>instance_id</title>
<meta name="generator" content="Adobe RoboHelp 2020" />
<meta name="generator" content="Adobe RoboHelp 2022" />
<link rel="stylesheet" href="../../../../assets/css/default.css" type="text/css" />
<script src="../../../../assets/scripts/main_script.js"></script>
<meta name="rh-authors" content="Mark Alexander" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>static_get</title>
<meta name="generator" content="Adobe RoboHelp 2020" />
<meta name="generator" content="Adobe RoboHelp 2022" />
<link rel="stylesheet" type="text/css" href="../../../assets/css/default.css" />
<script src="../../../assets/scripts/main_script.js" type="module"></script>
<meta name="rh-authors" content="Gurpreet S. Matharoo" />
Expand All @@ -15,9 +15,15 @@
</head>
<body>
<h1><span data-field="title" data-format="default">static_get</span></h1>
<p>This function returns the static struct for the given function, or <span class="inline2">undefined</span> if it has no static. The static struct is where all static variables for a function are stored.</p>
<p>You can also supply a struct, in which case it will give you the static struct for the constructor that was used to create the struct (or it may be a different struct if it was changed using <span class="inline3_func"><a data-xref="{title}" href="static_set.htm">static_set</a></span>).</p>
<p>When using constructor inheritance, static structs are chained, i.e. you can get the static struct of a static struct, if the constructor has a parent constructor.</p>
<p>This function returns the static struct for the given function or struct.</p>
<p>When you supply a function, this function returns the static struct for the function.</p>
<p>You can also supply a struct. What&#39;s returned depends on the struct: </p>
<ul class="colour">
<li>For a struct created from a constructor using the <span class="inline2"><a data-xref="{title}" href="../../GML_Overview/Language_Features/new.htm">new</a></span> keyword: the static struct for the constructor that was used to create the struct (or a different struct if it was changed after creation using <span class="inline3_func"><a data-xref="{title}" href="static_set.htm">static_set</a></span>).</li>
<li>For a static struct: the parent static struct in the <a data-xref="{text}" href="../../GML_Overview/Structs/Static_Structs.htm#h">Static Chain</a>. When using constructor inheritance, static structs are chained, i.e. you can get the static struct of a static struct, if the constructor has a parent constructor.</li>
<li>For any other struct: this struct&#39;s &quot;parent&quot; struct, which links the struct to the &quot;root&quot; struct.</li>
<li>For the &quot;root&quot; struct: <span class="inline2">undefined</span></li>
</ul>
<p>See: <a data-xref="{title}" href="../../GML_Overview/Structs/Static_Structs.htm">Static Struct</a></p>
<p> </p>
<h4>Syntax:</h4>
Expand All @@ -36,16 +42,16 @@ <h4>Syntax:</h4>
</tr>
<tr>
<td>struct_or_func_name</td>
<td><span data-keyref="Type_Struct"><a href="../../../../GameMaker_Language/GML_Overview/Structs.htm" target="_blank">Struct</a></span> or <span data-keyref="Type_Function"><a href="../../../../GameMaker_Language/GML_Overview/Script_Functions.htm" target="_blank">Function</a></span></td>
<td><span data-keyref="Type_Struct"><a href="../../GML_Overview/Structs.htm" target="_blank">Struct</a></span> or <span data-keyref="Type_Function"><a href="../../GML_Overview/Script_Functions.htm" target="_blank">Function</a></span></td>
<td>The struct or function for which to get the static struct</td>
</tr>
</tbody>
</table>
<p> </p>
<h4>Returns:</h4>
<p class="code"><span data-keyref="Type_Struct"><a href="../../../../GameMaker_Language/GML_Overview/Structs.htm" target="_blank">Struct</a></span> or <span data-keyref="Type_Undefined"><a href="../../../../GameMaker_Language/GML_Overview/Data_Types.htm" target="_blank">undefined</a></span> if no static struct is set</p>
<p class="code"><span data-keyref="Type_Struct"><a href="../../GML_Overview/Structs.htm" target="_blank">Struct</a></span> or <span data-keyref="Type_Undefined"><a href="../../GML_Overview/Data_Types.htm" target="_blank">undefined</a></span> (for the root struct)</p>
<p> </p>
<h4>Example:</h4>
<h4>Example 1:</h4>
<p class="code">function counter() {<br />
    static count = 0;<br />
    return count ++;<br />
Expand All @@ -63,6 +69,23 @@ <h4>Example:</h4>
<p>The above code creates a function <span class="inline2">counter()</span> with a static variable. The function is called repeatedly so its static variable&#39;s value is increased.</p>
<p>The static struct for that function is then returned, and stored in a variable (<span class="inline2">_static_counter</span>). Then it prints the static variable from the function, by first reading it from the function directly (<span class="inline2">counter.count</span>) and then reading it from the static struct (<span class="inline2">_static_counter.count</span>). Both print the same value, as they refer to the exact same variable.</p>
<p> </p>
<h4>Example 2: Going Up in the Static Chain</h4>
<p class="code">function item() constructor<br />
{<br />
    static hello = function()<br />
    {<br />
        show_debug_message(&quot;Hello World!&quot;);<br />
    }<br />
}<br />
function potion() : item() constructor {}<br />
<br />
my_potion = new potion();<br />
var _static_potion = <span data-field="title" data-format="default">static_get</span>(my_potion);<br />
var _static_parent = <span data-field="title" data-format="default">static_get</span>(_static_potion);<br />
_static_parent.hello();
</p>
<p>The above code first creates two constructors: a parent constructor <span class="inline2">item</span> with a single static function <span class="inline3_func">hello</span> and a child constructor <span class="inline2">potion</span>. It then creates a new <span class="inline2">potion</span> and stores it in a variable <span class="inline2">my_potion</span>. Next, a call to <span class="inline3_func"><span data-field="title" data-format="default">static_get</span></span> is made to get the static struct of <span class="inline2">my_potion</span>. The returned static struct, stored in a temporary variable <span class="inline2">_static_potion</span>, is part of the static chain. From this point, all further calls to <span class="inline3_func"><span data-field="title" data-format="default">static_get</span></span> will move up in the static chain. Another call to <span class="inline3_func"><span data-field="title" data-format="default">static_get</span></span> is made, which returns the static of <span class="inline2">item</span> and stores it in another temporary variable <span class="inline2">_static_parent</span>. Finally, this struct&#39;s <span class="inline3_func">hello</span> method is called.</p>
<p> </p>
<p> </p>
<div class="footer">
<div class="buttons">
Expand All @@ -71,7 +94,7 @@ <h4>Example:</h4>
<div>Next: <a data-xref="{title}" href="static_set.htm">static_set</a></div>
</div>
</div>
<h5><span data-keyref="Copyright Notice">© Copyright YoYo Games Ltd. 2022 All Rights Reserved</span></h5>
<h5><span data-keyref="Copyright Notice">© Copyright YoYo Games Ltd. 2023 All Rights Reserved</span></h5>
</div>
<!-- KEYWORDS
static_get
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Adobe RoboHelp 2022" />
<meta name="topic-comment" content="A note that explains that you have to call the function at least once before attempting to access the static struct" />
<title>Note_Warning_Static_Struct_Call_Once</title>
<link rel="stylesheet" type="text/css" href="../css/default.css" />
</head>
<body>
<p class="note"><span data-conref="Tag_warning.hts"> </span> You can&#39;t access a static variable from a function that was never called, as static variables are initialised on the first call to a function. Trying to do so will give you an error and crash your game.</p>
</body>
</html>

0 comments on commit 7ec6995

Please sign in to comment.