visit our site

Global variables in Swift are not variables

In Development, iOS, Mac OSX, Mobile

by AlexDenisov by June 11, 2014

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!).

UPD: shame on me, how could I miss this?

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.

tl;dr

Global variables are functions and their actual values instantiate on demand

The problem

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.

Explanation

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 from main.swift:

It 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 function main as an entry point, this function calls _top_level_code, which consists of main.swift. Let’s look at pseudocode of _top_level_code:

and get rid of ‘garbage’

Instead of direct access to variable, it calls respective function; let’s look at it:

it calls another function swift_once and returns actual variable globalVar. Ok, let’s go deeper, currently we’re interested in the second parameter: _globalinit_func0, it’s also function:

Caught it! Finally, we’ve found function which does exactly what we want:

Conclusion

Any global variable in Swift is being replaced with respective function call that initializes this variable on demand

Let’s wrap up our small research!

This code

translates 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!

Share
* Railsware is a premium software development consulting company, focused on delivering great web and mobile applications. Learn more about us.
  • Al Capone

    See the @lazy attribute in the documentation.

    • Alex Denisov

      Yeah, I saw it, but it seems I’ve missed this part at the bottom of the page:

      NOTE

      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.

    • Alex Denisov

      Shame on me >_<

  • Eonil

    That’s why its address keep changing!

  • Amr Ahmed Elghadban

    so how can we force it to be explicit have a value rather than lazy computed

    • Many things have changed since the publication.
      I can’t say whether it is possible now or not.

Signup for our weekly newsletter

Want to get more of Railsware blog?

RSS Feed

We're always ready to help!

Contact us