0

In his (great) series of books “You don't know JS", Kyle Simpson states that dynamic scope and this mecanism are "near cousin", he also says that :

"the this mechanism is kind of like dynamic scope." (YDKJS, Scope and Closure, Appendix A)

What is preventing him from saying that this is plain and simple dynamic scoping ?

Also, in the book "this & Object Prototypes", also part of the series YDKJS, as far as I can say, Kyle is not mentioning once dynamic scope while discussing how thisis working, so I am a bit surprised why he decided to not go further in the analogy... Does anyone have an idea why ? Thanks

godot
  • 1,550
  • 16
  • 33
  • 1
    I find it hard to categorize `this` in terms of scoping. I'd rather compare it to a *(hidden)* function argument that is filled by the JS engine, with the object that referenced the function for this particular function call. Although, there are utils (`.call()`, `.apply()`, `.bind()`) to fill this "argument" by yourself. – Thomas Jun 25 '17 at 17:14
  • `this` is not about scope. It is about binding. They are related but different concepts. It's a bit like the difference between throttle and clutch - both control power to the wheels but they are different things. Scope is about the visibility of variables - things related to scope are concepts like global variables, local variables and closures. Binding is about object resolution, about what object a method is operating on - things related to binding are `this` variables, method namespace resolution (automatic `this` - which C and Java have but javascript does not) and `super` variables – slebetman Jun 25 '17 at 18:15
  • @slebetman not sure this makes sense to me : `visibility` is just a - quite useful ! - anthropocentric metaphor to think about resolution (if my program "calls" the variable x, which value is it going to refer to ?). So it feels like the distinction you make is a bit based on circular reasoning... – godot Jun 25 '17 at 21:40

2 Answers2

4

The reason I claim this is just "kind of like" a dynamic scope and not actually a dynamic scope is based on these two observations:

  1. The aesthetic of accessing the "scope context" explicitly with an object reference (this.foo = 1) is distinct from implicitly accessing it via lexical variable reference (foo = 1). At best, this makes the two systems of "scope" parallel, not the same. But there's more different than what it seems on the surface!

  2. But more importantly, dynamic scopes are traditionally defined as scope chains that are based on the call-stack. That is, a dynamic scope is one where the decision of what "scope contexts" to consult, in order, is exactly the current stack of function calls. But this isn't based on the call-stack, per se, but rather just the manner in which the most recent call in the stack was made, only.

    Consider this scenario: foo() calls bar(), bar() calls baz(), and in baz() a reference is made to an x variable that is not defined in baz().

    • In lexical scope, the lookup would be baz(), then whatever the outer scope of baz() is, and so on. bar() and foo() wouldn't be consulted at all, unless they happened to be the lexically surrounding scopes of baz().

    • In dynamic scope, the call stack foo() -> bar() -> baz() is the scope chain, so baz() is consulted, then bar(), then foo(), regardless of where those 3 functions exist lexically in the code base.

    • Now, consider the same scenario, but this.x is the reference made inside baz(). The call stack foo() -> bar() -> baz() is not particularly relevant in resolving this.x. Rather, the only thing that matters is how baz() was invoked. If the call site is baz(), the "default binding" rule applies. If it's this.baz(), the "implicit binding" rule applies. If it's baz.call(..), the "explicit binding" rule applies. And if it's new baz(), the "new binding" rule applies. That's it.

    Actually, it's not the only thing, it's just the first decision that's made. Once it's determined what object (aka scope context object) this points to, now the only thing that matters is the prototype chain of that object, as that's the "scopes" that will be consulted, in order of the prototype chain linkage.


Summary:

  • In lexical scope, where a function is defined is the only thing that determines what contexts are used, and in what order, to resolve a variable reference.

  • in dynamic scope, where a function is called from is the only thing that determines what contexts are used, and in what order, to resolve a variable reference.

  • in this-based context, neither where a function is defined nor where it's called from are relevant. Therefore, this is neither lexical scoping nor dynamic scoping.

    The only thing that matters here is how the current function in the call stack (top of the stack) was called. Well, that's the only thing that matters to determine which scope chain to start the lookup on. But once that object is decided, it's now that object's prototype chain that entirely defines the scope resolution.

Kyle Simpson
  • 15,725
  • 2
  • 33
  • 55
3

Because the this "variable" is the only variable that has dynamic scope, all other ("real") variables have lexical scope in JavaScript. In contrast, in "plain and simple dynamic scoping", all variables have dynamic scope and you can't get away from it (which is really ugly). So when we want to have multiple values in our dynamic scope, we store them in an object, and access them as properties of the this object, which is quite different from dynamic scope and also involves object inheritance.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • interesting... But your starting argument is not totally convincing me as I would call a language in which "*all* variables have dynamic scope" a *pure* dynamic scope language (in the literature, there are plenty of accepted examples where some languages are described as involving a mix of scoping (e.g. [Wickham on R](http://adv-r.had.co.nz/Functions.html#lexical-scoping)). But maybe we could agree that `this` doesn't do enough to be called dynamic scope mecanism. – godot Jun 25 '17 at 19:03
  • @godot OK, I just thought that a mix of scoping wouldn't be called "plain and simple" any more, and that you were referring to such pure dynamic scope languages. But the "all" isn't the main point - it's that *arbitrary* variables should be dynamically scoped, whether individually selected or by default. `this` is a single identifier name, and it's not even a variable but a special keyword that cannot be assigned to (though it can and often does hold a mutable object). – Bergi Jun 25 '17 at 20:49
  • thx, your answer is quite convincing (maybe you could edit you previous answer). In the end, I would say that `this` share some mechanisms with the concept of dyn. scop. - i.e. resolution through call-site - but maybe not enough to be called dynamic scope. But to go back to the analogy with R. There are similar mecanism that are defined as dynamic scoping (the use of [`parent.frame()` in `eval()`](http://adv-r.had.co.nz/Computing-on-the-language.html#scoping-issues) ), so it feels still a bit conventional whether to call `this` dyn. scop or not... – godot Jun 25 '17 at 23:29