adam tecle

Static vs dynamic dispatch

Aug 08, 2017

When something is allocated statically, its size is fixed when the program is created. Primitive types like int, boolean, char, are allocated statically, i.e. on the stack.

Take a look at this function:

func foo() {
  let x = 2
  let y = 2
  print(x + y)
}

When this function is called, a block is reserved on the top of the stack for local variables and bookkeeping data. In this case, we would allocate some space on the call stack for x and y. When this function finishes executing, the stack is popped, and the memory we allocated for x and y is released.

This is in contrast to dynamic allocation, where the lifetime of allocated memory is managed by the programmer, or in some languages, by a garbage collection mechanism.

class Person {
  let name: String
  var friends: [Person]

  func addFriend(_ friend: Person) {
    friends.append(friend)
  }
}

func foo(person: Person) {
  let friend = Person(name: "Adam")
  person.addFriend(friend)
}

Here, we allocate memory on the heap for friend, and also for extra space in the friends array if needed. The lifetime of friend is not determined by the function scope, but by its reference count.

With static allocation, we avoid the overhead of calling malloc(), which has to scan for a free block of memory, possibly resize it, mark it used, etc. The OS is able to allocate a fixed amount of space on the stack, then accessing the statically allocated variable is a matter of bumping the stack pointer. The big O complexity of memory allocation is improved by not having to find a chunk of memory to allocate.

Operations on the struct are also dispatched statically. Meaning, the compiler has insight into exactly what will be executed on a struct. As opposed to dynamic dispatch, where implementations have to be looked up at runtime. Because the compiler knows what’s going to be executed, it can optimize the generated machine code.

For more on static vs dynamic dispatch, check out this and this