0:00

Um,why exactly does all this matter? So.

Â It's not immediately clear.

Â No.

Â So typically the function is defined the global environment so that

Â values of the free variables are just found in the user's workspace.

Â So this is kind of the.

Â The right thing to do is kind of what most people are expecting.

Â If there's no, if, if there's, you can't find a value

Â inside the function itself, you just look in the global environment.

Â So this is the, the idea here is that you can define things like

Â global variables, that will be common to a lot of different functions.

Â That you might be defining in your workspace.

Â 0:33

so, but the key difference in R is

Â that you can define functions inside of other functions.

Â 'n so for example a function can return a function as the return value.

Â So, in most functions they'll return a list, or a vector, or a matrix, or

Â a data frame or something like that, but it is possible for a, for a function

Â to return another function and then that, if that's

Â the case then the, then the function that gets returned.

Â It was defined inside of another function.

Â So, it's an, the environment in which it was defined Is not the global environment.

Â It's really the, the, the insides of this other function.

Â So this is when things get interesting and this is when

Â the scoping rules really have an impact on what you can do.

Â 1:17

So, I am going to define a very simple function here and often

Â these kinds of functions come [UNKNOWN]

Â where you might think of constructive functions.

Â So, the idea that the function is constructing another function.

Â So, here's what I want to, I want to

Â create a function that that defines another, called make.power.

Â And what make.power takes as input is a number n.

Â Okay?

Â So, and inside the make.power function I define

Â another function called pow.

Â And pow is going to take an argument called x.

Â And and so what's going to happen is that

Â the power function is going to take the, then the,

Â take the argument X and raise to their

Â power N, okay, and so make that power returns,

Â with a function power as its return value and so you see inside the power function X

Â is a, X is a function argument but that's not a problem, but n is a free variable

Â because its not defined inside the power. Function.

Â However, N is defined inside the make.power function and so

Â since that's the environment in which the pow is defined.

Â It will find the value of N.

Â The pow, the power function will find the

Â value of n inside this, it's other environment.

Â So what happens is that I can call make.power and pass it a number like 3.

Â And then, it will return a function, which I'll sign to

Â be called cube.

Â And, similarly, I can pass 2 to make that

Â power and create a function that I'll call square.

Â So, now, when I, when I pass cube, the number 3 What is

Â it does is it raises 3 to the 3rd power, so I get 27.

Â If I call square on the number 3, it, it

Â raises three to the 2nd power, so it gives me 9.

Â And so, so, so now, I've cons, I've

Â got one function that can, that's capable of constructing

Â many different types of functions, and by raising to pow, to various powers.

Â 3:07

So, how do you know what's in a function's environment?

Â So you can, you can at the function, so, excuse me.

Â You can look in the environment in which

Â the function was defined, by calling the LS function.

Â So if I call, if I call LS on On the environment for cube.

Â You can see that inside the cube function, there's,

Â there's something, there's an, there's an object called N.

Â And if I use get on N you'll see that the value of N is equal to 3.

Â So that's how the power function knows to raise

Â it to the 3rd, to the 3rd power.

Â Excuse me, that's how the cube function knows how to, knows

Â to raise the argument to the 3rd power because it's already defined.

Â In it's, in it's, in it's, closure environment.

Â Similarly the environment for square, you can see

Â it has the exact same objects in it.

Â But now the value of n is equal to 2, in the square function.

Â 3:52

So, so, I want to make one brief

Â comparison between lexical scoping, which is what R

Â does, and dynamic scoping, which is what maybe

Â some other function, some other programing languages implement.

Â So here I've got, I'm assigning the value of Y equal to 10.

Â Then create a function F, which takes, as an argument, X.

Â 4:11

And then, it assigns, there it assigns Y equal to 2, it squares Y and then adds G

Â of X. So, what's G?

Â G is another function, which takes as an

Â argument called X, and it multiplies X times Y.

Â So, in the F function, Y is a free variable, and G is also a free variable.

Â So, the G function is not defined.

Â Inside of F of or, it's, it, of, argument to F.

Â Then in the G function, then the var-, the symbol Y is a free variable.

Â And so the question

Â is if I call f of 3 what gets returned?

Â 4:49

So with lexical scoping, the value of Y and the function G

Â is looked up in the environment in which the function was defined.

Â Which in this case was the global environment.

Â So that the value of Y and the G function is 10.

Â So with dynamic scoping the value of Y is looked up in

Â the environment from which the function

Â was called; sometimes called the calling environment.

Â So in the R the calling environment is

Â known as is what's called the parent frame.

Â 5:30

So, the one thing that, that, that will

Â make lexical scoping and dynamic scoping look the

Â same is that when a function is defined

Â in the global environment and is subsequently called

Â from the global environment, then the defining environment

Â and the calling environment are exactly the same

Â and so this can sometimes give the appearance

Â of dynamic scoping even when It doesn't exist.

Â So here I've got a function called G.

Â It takes an argument X. It assigns A to be equal to 3.

Â And then it adds X plus A plus Y.

Â So, in this case, X is a function is a formal argument.

Â A is a local variable so it's not a

Â formal argument, but I defined it inside the function.

Â Then so, that's okay.

Â And then Y is a free variable, okay?

Â So if I call G of 2, the function G is

Â going to look for the value of Y in the global environment.

Â If I haven't yet defined Y then there has

Â to be an error because it doesn't know what

Â value to assign to the symbol of Y. So that's what I get in this line here.

Â Now if I define what Y is, say I assign it to be 3, if I call it

Â G of 2, then it returns 8 because now it's able to find Y in the global environment.

Â So even though it looks like the value of Y was looked up in the calling

Â environment, it's actually the defining environment because G

Â happened to be defined in the global environment

Â 7:10

So, one of the main consequences of lexical scoping in R

Â is that all the objects have to be stored in memory.

Â So, if you're working with a programming language that has

Â very small objects this generally speaking not a big problem.

Â but.

Â Because of nature of the scoping rules and

Â because of the complexity of the environment and the,

Â the way they are all linked together, it's difficult

Â to implement this type of model outside of physical

Â memory, and so.

Â 7:38

So the consequence was that, when R was originally designed.

Â Everything was stored in memory.

Â Things are getting complicated now, because of very large types of data sets.

Â And, being able to read them into R.

Â It is a challenge. Everything has to be stored in memory.

Â 7:53

Second now, so every function has a carrier

Â pointer to its respect, to its defining environment.

Â and, and that defining environment could literally be anywhere

Â because there could be functions within functions and then the,

Â and if you do, if one function returns another function,

Â 8:08

then there has, there has to be a pointer to

Â that piece of memory where the defining environment is stored.

Â And so this makes the model a little bit

Â more complex but but, but all the more useful.

Â So, the, in S plus, which was kind of the original implementation of the S language,

Â the free variable were always looked up in the workspace.

Â Everything could be stored on the disk, because the

Â defining environment of all the functions was the same.

Â