Dynamic vs Static
Dynamic and Static frameworks

  Mar 12, 2020 -   read
  ios, swift, tips, dynamic, static

When someone says something is dynamic, it usually means things could change. Dynamic array, meaning the content of the array could change, or a dynamic system could mean a system that is robust and can adapt to different input scenario.

So, what does it mean for a framework to be a dynamic framework, or static framework? Or when someone says Python is a dynamically typed language but Swift is a statically typed language?

Let’s dive in.

To understand the concept more clearly. Let’s first revisit how the computer program works.

  • A program is written in some programming language in the form of code.
  • The code is then checked for validity of syntax by either a code linter, or a code compiler
  • Then the code is compiled
  • Then the code is run.

So if everything is working fine, the code will be executed by the computer and it does what it is supposed to do.

So what does it mean when we say ‘be executed by the computer’ ?

We know eventaully the programming code has to be translated into a machine code (0s and 1s). The CPU will execute the machine code by calling the registars available. So when we say code is compiling, the time needed to convert the human read codes into a machine code is called compile time. And when the machine code is being executed by the CPU, the time it takes to load the machine code into cpu is called run time.

Compiler

So compiler takes in the human readable code and converts it into a machine code that the CPU can execute. Normally, there are a lot of steps involved while translating the code into machine code. Typical steps involved can be summaries as follows:

  • Lexical Analysis: Breaks down the code into a sequence of lexemes (called tokens). So it will identify keywords, if, else, while terms, valid characters used by the language. If it encounters a character that’s not recognised, the compiler will fail and throw some error.
  • Syntax Analysis: Reads the sequence of tokens generated in step 1 and creates a Abstract Syntax Tree (AST). This step will be able to identify if there are any syntax issues. For eg. if there’s a missing } brance.
  • Semantic Analysis: It uses the AST to check if the prgram is consistent with all the rules of the source programming language. This step involves type checking, type interface, symbol management, etc. The output of this step will be annotated AST.
  • Intermediate code generation: Uses annotated AST to generate intermediate and machine-independent codes, eg. three-address code. A three-address code is a code that takes max 3 operands. It’s of the format: a := b <operator> c.
  • Optimization: The compiler uses the intermediate code and optimizes to make the code faster and shorter.
  • Code generation: Finally the optimized code is translated into machine-depenedent code like Assembly or other low level code.

Intrepretor

Generally interpretor will do the first phases of compiler, i.e. up to the steps of generating Machine indpendent intermediate code. The intrepretor is able to quickly evaluate the intermediate code when it is run.

Dynamic vs Static typed languages:

These refer to when the type checking happens. Type checking may happen during compile time, or during run time. If it happens during compile time, it is called “static type”. If it happens on the fly (or during run time) it is called “dynamic type”.

Type-cheking is done to ensure the program is type-safe.

  • Dynamically-typed languages do not require you to declare the data types of your variables before you use them. For example in python this code is fine.
data = 10;
data = Hello World!”; // no error caused

And this is also does not throw error if a is always greater than 0.

def foo(a):
    if a > 0:
        print 'Hi'
    else:
        print "3" + 5foo(2)

If the above code was written for a static type language like Go or Swift, compiler will check for type-safety and never allow this to be compiled.

So we can see, with static type language, the compiler can help guarantee the type-safety, and can also optimize the code because it is aware of the type of variables.

Dynamic vs Static Library (Framework)

This is entirely different from dynamic or static typing.

Static library means a unit of code that is linked during compile time and it won’t change during run time.

Dynamic library means a unit of code/assets that is linked during run time and it may change.

In the context of cocoa touch, Framework means a library plus assests (in the form of bundle).

Typically all the apple’s native frameworks, eg. UIKit, Foundation, AV are dynamic frameworks. When the code to run an iOS app is built, only the code that user has written and the static libraries (eg. Google Analytics static library) is compiled. The dynamic library is loaded when the app is actually being run on the phone.

The advantage of dynamic framework is, the app can automatically (without having to rebuilt) take advantage of updates in the dynamic libraries. Whereas with static framework, if there are any changes, the app has to be recompiled and rebuilt.

Dynamic frameworks are not compiled, so overall comile time of the app is less, and the size of the binary is also less.

Because static frameworks are compiled and linked to the app, they tend to increase the size of the app.

More on this topic can be found here

Static library:

Dynamic library:

ABI Stability

In the above definition of dynamic framework, we saw that the dynamic libraries are not compiled, a memory reference for the library is created and during run time the library will be dynamically loaded (using dlyb loader). So we can see there needs a way for the compiled code to be able to access the dynamic library that the OS provides. This interface is what’s typically called an ABI (application binary interfact).

ABI stability is a game changer. If there were no ABI stability what could go wrong.

Imagine my app is compiled with swift 4.0. The ABI says look for dynamic libraries (eg. UIKit) that are written with swift 4.0 on the phone. If for some reason, the new OS running on the phone does not have the dynamic libraries for the swift 4.0 (say it only has version 5.0), the dynamic libraries can’t be loaded. Even if the dynamic libraries of version 5.0 were to be loaded, the app may not perform the way it was supposed to because the libraries interface are changed.

So what happens when there is no abi stability?

When the app is created for the app store release, the OS will bundle the dynamic libraries and embed them onto the app. This means the size of the app is significantly higher than it could have been.

With ABI stability, the OS can gurantee that if the app was built using a stable version of swift (swift 5.0 and onwards have the ABI stability), the app will still run if the underlying OS is now upgraded to have swift version 6.0.

Let’s see the image below:

In this example, an app built with Swift 5.0 will run on systems that have a Swift 5 standard library installed, as well as those with a hypothetical Swift 5.1 or Swift 6.

From the swift blog:

ABI stability for Apple OSes means that apps deploying to upcoming releases of those OSes will no longer need to embed the Swift standard library and “overlay” libraries within the app bundle, shrinking their download size; the Swift runtime and standard library will be shipped with the OS, like the Objective-C runtime.

Module Stability

ABI stability is picking the right and compatible version of dynamic library during run time. Module stability is making sure the stability of third party modules can be established during run time as well.

Currently swift uses swiftmodule, an opaque archive format to describe the interface of a library. In C, this is represented as a header file. swiftmodule format is tied to the compiler. Meaning if a framework was written with a compiler running on version X and the developer tries to import that framework with his compiler running on Version X+1, then the import will fail. Module stability is an ongoing update on swift to fix this problem. If the framework is built with module stability (which basically means instead of using opaque swiftmodule format, clarify the interfact in textual format), the future versions of compiler can also use the framework written in previous version.

!! Happy coding !!

Suraj Pathak
Swift Brewer