There's a couple of random examples of what dynamic scope is. So the bash scripting language uses dynamic scope. There's an opt-in mode of Perl that allows Perl to operate in a dynamic scoping fashion. And there's some old academic languages that use the name scope. But for the vast majority of languages you've ever dealt with, you've dealt with scoping in the lexical scoping model.
What does the name lexical mean? Well that's kind of a fancy term that the lex, that refers to the parsing stage called lexing that occurs in the compiler when it's parsing through your code. The takeaway from that is that lexical scope Means compile time scope. In other words, at the time that you wrote your code, and that code then got compiled, the decisions for how all the scoping were going to occur were made in stone at point.
There were no more decisions about scope that were to be made beyond that lexical phase. So the compiler decides what your scope is and we already that. We saw implicitly that when we walked through our code, and we walked into a function, because there was a function there that created a new unit of scope, and any declarations inside of it were attached to that new nested scope.
It's going to look weird, but I'm going to give you a comparison because I want you to be able to compare dynamic scope to something that we're going to see a little bit later, which is the okay? All right, I'm going to give you this metaphor, this diagram. It's a highly technical diagram.
It's a metaphor for you of what we've been talking about with scoping, and I want you to ignore the, right hand side of the diagram for now. That we will explain as we go through out the rest of the day, okay? We won't understand most of the right hand side until the end of today, or most of the way to the end.
But on the left hand side we see Lexical Scope, and I want you to think of it like a building. It's kind of like the current scope is the first floor of the building. I'm looking for something on the first floor. I either find it there or I don't, and if I don't find it there, what do I do?
I go up one level of my scoping and I go out one level in my scoping it's kind of metaphorically, like taking the stairs or the elevator up to the second floor of my building and looking for it there. And going to the third floor, the fourth floor, and the fifth floor, and eventually I get to the top floor of the building which represents the global scope.
I either find it there or I don't but there's no more floors to go to. Okay. So I want you to metaphorically think of this lexical scope traversal that we've been talking about, as like going up the floors, up the elevator of a building, okay. Another way of visualizing it, a little bit more sort of attached to this code, is the idea of nested scope bubbles.
So there's a bubble around the scope of baz, and there's a bubble around the scope of foo, and there's a bubble around the outer enclosing closing scope, in this case, the global scope. And what I want you to notice about these bubbles is that they are strictly nested within each other.
This is not like Venn Diagrams, where we have bubbles overlapping with each other. You can't have the scope of foo partially in two other scopes or whatever, it's strictly nesting that's occurring here, okay? Now, what's interesting about this nesting is, the nesting that occurs is fundamental to the way lexical scope works.
The fact that baz is inside of foo, as opposed to outside of foo, is an irrevocable decision that you made at author time. You chose to put baz inside of foo which means you chose to next the scope bubble of baz inside of the scope bubble of foo.
So these are author timed decisions, or what we call compile time decisions for how the scope works. What this means is that the compiler, when he's processing through this code, and he processes the outer bubble, and then the inner bubble, and then finally the smallest bubble in the middle.
When he processes through those nested scopes, he knows exactly what the scope looks like, because it can't change. It's an author time decision, and your code isn't going to change itself at author time, I mean at run time. So it knows ahead of time, even though we conceptually talked about that whole idea of like looking in my current scope, and then going to the next one or whatever.
Doesn't actually have to do that, because it knows it can pile time where everything is, and it can cache all of those references. So from an optimization perspective, it knows categorically, where bar is already doesn't need to look in baz, because it knows exactly where bar is already.
So as it's compiling, it can cache all these references. It's an author time decision about your scope. So you made the choices about where you put your functions at the time that you offered your code.