The problem

#include <iostream> int globalFunc() { std::cout << "hello, world!

"; return 42; } int globalVar = globalFunc();

int main(int argc, const char * argv[]) { return 0; }

import Foundation func globalFunc() -> Int { println("hello, world!") return 42 } var globalVar = globalFunc()

// currently, this file is empty

Explanation

(lldb) po globalVar hello, world! 42 (lldb)

main.swift

var localOne = globalVar

main

_top_level_code

main.swift

_top_level_code

function _top_level_code { rax = __TF10swift_testa9globalVarSi(); rax = *rax; *__Tv10swift_test8localOneSi = rax; return rax; }

v_localOne = F_globalVar();

function __TF10swift_testa9globalVarSi { swift_once(_globalinit_token0, _globalinit_func0, 0x0); return __Tv10swift_test9globalVarSi; }

swift_once

globalVar

_globalinit_func0

function _globalinit_func0 { rax = __TF10swift_test10globalFuncFT_Si(); *__Tv10swift_test9globalVarSi = rax; return rax; }

v_globalVar = F_globalFunc()

Conclusion

func globalFunc() -> Int { println("hello, world") return 42 } var globalVar = globalFunc()

var localOne = globalVar

func F_globalFunc() -> Int { println("hello, world") return 42 } var v_globalVar_init = 0 var v_globalVar = zero func F_globalVar_init() { v_globalVar_init = 1 v_globalVar = F_globalFunc() } func F_globalVar() { if (v_globalVar_init == 0) { F_globalVar_init() } return v_globalVar } // .... var v_localOne = F_globalVar()

The title sounds pretty strange, but I will explain what it means.While playing with Swift I’ve faced weird behaviour, a feature in fact, which isn’t covered in documentation (at least I didn’t find any references!).shame on me, how could I miss this?I wanted to perform some function from different translation unit without explicit calling, and decided to try old C++ trick with global variable:After compiling and running this program you’ll see “hello, world!” in the output, so I’ve tried the same trick with swift:But had no luck… This program does nothing in swift.At the first glance, it looks like compiler optimisation, but what if we call this variable from debugger?It works. Weird. But it works!Ok, so let’s access to this variable fromIt works as well, so variable instantiates at the first call. But how it works and why? To understand how it works we definitely should dive deeper into the executable. Usually I’m using LLVM IR for such purposes, but this time I decided to use Hopper , ’cause it has a very useful feature: ‘Show pseudocode’After opening the executable via Hopper you may see that app also has functionas an entry point, this function calls, which consists of. Let’s look at pseudocode ofand get rid of ‘garbage’Instead of direct access to variable, it calls respective function; let’s look at it:it calls another functionand returns actual variable. Ok, let’s go deeper, currently we’re interested in the second parameter:, it’s also function:Caught it! Finally, we’ve found function which does exactly what we want:Let’s wrap up our small research!This codetranslates into this one:So, now this behaviour is clear, but question ‘why such a decision was made?’ is still open.Happy hacking, guys, and be careful!