Thank you for such a precise write up.
Mauro Bringolf

Mauro Bringolf, thanks, glad it’s useful.

The semantics of an instance reference (that is this value) may depend on the implementation. Yes, it is not something what is set or “captured” when a method is created. Instead, it is set (or simply passed) by the caller.

As was mentioned, dynamic scope can easily be replaced by function parameters, and explicitly passing them when a function is called. And this approach is used in Python or Rust, when self is just passed as the first argument.

# Python
class C(object):
def method(self):
print("x: ", self.x)
foo = C()
foo.x = 10
foo.method() # x: 10
# Same as:
C.method(foo) # x: 10

In JavaScript this value is dynamically scoped, since even if a function is created within a method call, it doesn’t capture this (unless it’s an arrow function which does capture this):

// JavaScript
var x = 'global';
var foo = {
x: 10,
  method() {
console.log(this.x); // 10
    // Create `foo` function which uses dynamic `this`:
function foo() {
    foo(); // 'global', not 10
    // Create `bar` function which uses static `this`:
const bar = () => {
    bar(); // 10

Regarding lower level, the this value may again be passed differently depending on the implementation: it might be passed on the stack as other parameters, or in a register (usually in %ecx), or even on the heap, if a stack frame is allocated there.

Procedures are still called by creating an activation frame (which usually stores parameters, and local variable). The activation frame can be allocated (usually) on stack, or on heap (if there is closure).

The dynamic vs. static scope in this case is related to free variables used by a function.

If a language uses static scope, then the captured frame (which contains that free variable) is set as a parent frame of the activation frame: so if variable is not found in the own activation frame, it’s looked up in the saved frame.

And in case of the dynamic scope, a new (or intermediate) frame can be created specifically to set values for free variables. And again, this frame is set as a parent frame of the activation frame, so the free variable is found there — but with the value provided by the caller.

Still, technically these frames on lower level can be allocated on the stack or on the heap.

Show your support

Clapping shows how much you appreciated Dmitry Soshnikov’s story.