{"id":6925,"date":"2014-06-11T14:21:43","date_gmt":"2014-06-11T11:21:43","guid":{"rendered":"http:\/\/railsware.com\/blog\/?p=6925"},"modified":"2021-08-12T13:01:13","modified_gmt":"2021-08-12T10:01:13","slug":"global-variables-in-swift-are-not-variables","status":"publish","type":"post","link":"https:\/\/railsware.com\/blog\/global-variables-in-swift-are-not-variables\/","title":{"rendered":"Global variables in Swift are not variables"},"content":{"rendered":"\n<p>The title sounds pretty strange, but I will explain what it means.<\/p>\n\n\n\n<p>While playing with Swift I&#8217;ve faced weird behaviour, a feature in fact, which isn&#8217;t covered in documentation (at least I didn&#8217;t find any references!).<\/p>\n\n\n\n<p><strong>UPD:<\/strong> shame on me, how could I miss this?<\/p>\n\n\n\n<p><strong>Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties. Unlike lazy stored properties, global constants and variables do not need to be marked with the @lazy attribute.<\/strong><\/p>\n\n\n\n<p><strong>Global variables are functions and their actual values instantiate on demand<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The problem<\/h2>\n\n\n\n<p>I wanted to perform some function from different translation unit without explicit calling, and decided to try old C++ trick with global variable:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:c++ decode:true toolbar:1\">#include &lt;iostream&gt;\n\nint globalFunc() \n{\n    std::cout &lt;&lt; \"hello, world!\\n\";\n    return 42;\n}\n\nint globalVar = globalFunc();<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted lang:c++ decode:true toolbar:1\">int main(int argc, const char * argv[])\n{\n    return 0;\n}<\/pre>\n\n\n\n<p>After compiling and running this program you&#8217;ll see &#8220;hello, world!&#8221; in the output, so I&#8217;ve tried the same trick with swift:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:go decode:true\">import Foundation\n\nfunc globalFunc() -&gt; Int \n{\n    println(\"hello, world!\")\n    return 42\n}\n\nvar globalVar = globalFunc()<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:go decode:true\">\/\/ currently, this file is empty<\/pre>\n\n\n\n<p>But had no luck&#8230; This program does nothing in swift.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Explanation<\/h2>\n\n\n\n<p>At the first glance, it looks like compiler optimisation, but what if we call this variable from debugger?<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:2 lang:default decode:true\">(lldb) po globalVar\nhello, world!\n42\n\n(lldb)<\/pre>\n\n\n\n<p>It works. Weird. But it works!<\/p>\n\n\n\n<p>Ok, so let&#8217;s access to this variable from <code>main.swift<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:go decode:true\">var localOne = globalVar<\/pre>\n\n\n\n<p>It works as well, so variable instantiates at the first call. But how it works and why?<br>To understand how it works we definitely should dive deeper into the executable. Usually I&#8217;m using LLVM IR for such purposes, but this time I decided to use <a title=\"Hopper\" href=\"http:\/\/www.hopperapp.com\" target=\"_blank\" rel=\"noopener\">Hopper<\/a>, &#8217;cause it has a very useful feature: &#8216;Show pseudocode&#8217;<\/p>\n\n\n\n<p>After opening the executable via Hopper you may see that app also has function <code>main<\/code> as an entry point, this function calls <code>_top_level_code<\/code>, which consists of <code>main.swift<\/code>. Let&#8217;s look at pseudocode of <code>_top_level_code<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:js decode:true\">function _top_level_code {\n    rax = __TF10swift_testa9globalVarSi();\n    rax = *rax;\n    *__Tv10swift_test8localOneSi = rax;\n    return rax;\n}<\/pre>\n\n\n\n<p>and get rid of &#8216;garbage&#8217;<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:js decode:true\">v_localOne = F_globalVar();<\/pre>\n\n\n\n<p>Instead of direct access to variable, it calls respective function; let&#8217;s look at it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:js decode:true\">function __TF10swift_testa9globalVarSi {\n    swift_once(_globalinit_token0, _globalinit_func0, 0x0);\n    return __Tv10swift_test9globalVarSi;\n}<\/pre>\n\n\n\n<p>it calls another function <code>swift_once<\/code> and returns actual variable <code>globalVar<\/code>. Ok, let&#8217;s go deeper, currently we&#8217;re interested in the second parameter: <code>_globalinit_func0<\/code>, it&#8217;s also function:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:js decode:true\">function _globalinit_func0 {\n    rax = __TF10swift_test10globalFuncFT_Si();\n    *__Tv10swift_test9globalVarSi = rax;\n    return rax;\n}<\/pre>\n\n\n\n<p>Caught it! Finally, we&#8217;ve found function which does exactly what we want:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:go decode:true\">v_globalVar = F_globalFunc()<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p><strong>Any global variable in Swift is being replaced with respective function call that initializes this variable on demand<\/strong><\/p>\n\n\n\n<p>Let&#8217;s wrap up our small research!<\/p>\n\n\n\n<p>This code<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:go decode:true\">func globalFunc() -&gt; Int\n{\n    println(\"hello, world\")\n    return 42\n}\n\nvar globalVar = globalFunc()<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:go decode:true\">var localOne = globalVar<\/pre>\n\n\n\n<p>translates into this one:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted toolbar:1 lang:go decode:true\">func F_globalFunc() -&gt; Int\n{\n    println(\"hello, world\")\n    return 42\n}\n\nvar v_globalVar_init = 0\nvar v_globalVar = zero\n\nfunc F_globalVar_init()\n{\n    v_globalVar_init = 1\n    v_globalVar = F_globalFunc()\n}\n\nfunc F_globalVar() \n{\n    if (v_globalVar_init == 0) {\n        F_globalVar_init()\n    }\n    return v_globalVar\n}\n\n\/\/ ....\nvar v_localOne = F_globalVar()<\/pre>\n\n\n\n<p>So, now this behaviour is clear, but question &#8216;why such a decision was made?&#8217; is still open.<\/p>\n\n\n\n<p>Happy hacking, guys, and be careful!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The title sounds pretty strange, but I will explain what it means. While playing with Swift I&#8217;ve faced weird behaviour, a feature in fact, which isn&#8217;t covered in documentation (at least I didn&#8217;t find any references!). UPD: shame on me, how could I miss this? Global constants and variables are always computed lazily, in a&#8230;<\/p>\n","protected":false},"author":55,"featured_media":9454,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[],"coauthors":["AlexDenisov"],"class_list":["post-6925","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"aioseo_notices":[],"categories_data":[{"name":"Engineering","link":"https:\/\/railsware.com\/blog?category=development"}],"post_thumbnails":"https:\/\/railsware.com\/blog\/wp-content\/themes\/railsware\/vendors\/images\/article-thumbnail-default.jpg","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/6925","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/users\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/comments?post=6925"}],"version-history":[{"count":38,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/6925\/revisions"}],"predecessor-version":[{"id":13958,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/6925\/revisions\/13958"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media\/9454"}],"wp:attachment":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media?parent=6925"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/categories?post=6925"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/tags?post=6925"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/coauthors?post=6925"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}