Transcript from the "Closure and Side Effects" Lesson
>> Kyle Simpson: Our next topic of discussion is closure. How many of you ever either had or given or both the job interview question what is closure? Anybody? Okay, I see a few hands maybe some people online will resonate with that. I For a long time before becoming a teacher, I've been a developer now for about 20 years, so I've only been teaching the last five or so.
[00:01:03] With the job interview questions and I countless times asked this question, what is closure? Tell me about closure, tell me an example of using closure in your code some variation thereof. [COUGH] Most of the answers that I would get would range somewhere around, it has to do with asynchronous callbacks, click handlers, timers, things like that.
[00:01:27] And I would say okay, let me prompt you to give me something more, right? What exactly does that mean? Yes, we know that asynchronous callbacks happen in code, but what does it mean to have closure? And when pressed most people didn't have much more to articulate on the topic.
[00:01:42] They've heard of closure but never really processed in their mind what it was. Closure I think can be said to be if not one of them, if not the most certainly in the top 2 or 3 most important Concepts, most prevalent concepts ever invented in all of computer science.
[00:02:04] One of the original ones, actually, it's been around since very, very early days of programming. There is a talk that Doug Crockford gave at one point, he was talking about this topic. He was gonna introduce closure and he was talking in the general sense about anytime a really truly great idea gets invented.
[00:02:30] He would assert that historically, it always takes a full generation of programmers before that truly great idea catches on. And he gave several examples of that, but his somewhat tongue and cheek explanation for why it takes so long for a great idea to catch on is that all of the existing crew are resistant to change.
[00:02:53] They like things the way they are. They don't see any reason why we need to change. And so we basically just have to wait around long and if for them to retire or die off Before the new crowd can come in and say hey this great thing is what we ought to do.
[00:03:08] There's a little bit of truth to that, but obviously it's a little bit overboard. But then he goes on to say, and this is to the point of closure, he goes on to say we know that closure is truly great cuz it took two full generations to catch on.
[00:03:45] Use closure to any power, but at the time, there really weren't that many, if any mainstream consumer oriented languages that had closure in them. We had Pearl, you could argue around the same time, 95, 96, 7. Pearl was coming into its own, and Pearl definitely introduced closure, you could argue that it was a rival in that respect.
[00:04:52] And he wanted to put Scheme in the browser, and Netscape was like, yeah that sounds great, come work for us. And as soon as he showed up, they were like no, we're not putting Scheme in the browser. And so he's like, well, How do I do my favorite language that I like in Scheme?
[00:05:07] How do I get those concepts into the browser? So we developed this language that looks like Java, because that's what they told him, they said make it look like Java. But under the covers it really is more related to Scheme, a functional programming language, so he laid the foundation for closure.
[00:05:25] In those earliest days of java script and I think that was a unique almost accidental genius. A stroke of genius to marry this procedural or even class object oriented syntax with these functional concepts. Really I think one of the first mainstream if not the first mainstream language to do so and truly embody the idea of a multiparadigm language.
[00:06:09] You could do procedural, object oriented, or functional. It's not that you could do that, but you could actually mix and match those different paradigms within the same program. And I found that to be fascinating, because ultimately, I like to consider, I get accused a lot of being sort of an ivory tower.
[00:06:26] I'm disconnected from reality cuz all I do is teach but I write a lot of code and I spend a lot of time in your shoes and I like to consider myself ultimately a pragmatist. And what I liked about multi-paradigm is that I didn't have to choose, I could pick which one was correct for any given situation.
[00:07:06] Certainly, all the consumer orientated ones, they all have closure. Java added closure, PHP added closure. We have Ruby and Python that came along, they all have closure. Every main stream language out there has closure. Even ones that we wouldn't have thought of, like C++ for example. It has closure in it because it turns out it's actually a pretty great idea.
[00:07:27] Turns out it's so powerful that we can implement so many other things on top of it. It is highly prevalent and certainly for the functional program, closure is at the heart of everything that we do. Pretty much everything that we do. We've already been using a bunch of closure up to this point in the code snippets that we've been doing and you might not just have realized what it was.
[00:07:51] So the next time you either give or get asked that interview question, what is closure? Call me crazy, but I'd love for you to have a very specific, articulate answer to that question. Cuz it's a real thing that can actually be recognized and studied and used and understanding what you're talking about instead of, you know it's about call backs.
[00:08:16] Not only I think it will help you get the job but I think it will help you write better code if you understand what you're talking about. So, I wanna give you a definition for closure that you can feel free to use the next time you got asked that question.
[00:08:29] Or feel free to ask this of others and use this as the standard to measure by, it is not the academic definition for closure. If you go on Wikipedia and you try to study what is closure, you're gonna get a whole variety of different descriptions for things and they may or may not line up in various parts.
[00:08:47] Your mileage may vary, as they say, but this is the most distilled down pragmatic definition that I've been able to come up with for what closure is in my experience. And it's based purely on what we can observe about closure. Philosophically, it's just like the if the tree falls in the forest and no one's around to hear it, thing.
[00:09:12] We all know what this is, right? Does it make a sound? Well, if a closure exists academically, but there's no way to observe that closure, does it actually matter whether it exists? I would say not really, so I choose to define closure based upon how we can observe it being different and observation is a really key point here.
[00:09:56] But rather, help you identify, help you be sensitive to observe that as you use it in your programs and to use it on purpose. To use it intentionally and to avoid accidentally having it do stuff that you don't want. There's also a pretty good chance that some of you have had bugs in your program directly related to closure and you may not have realized that that was the problem.
>> Kyle Simpson: So let's have a good, clear definition for closure, here it is. Closure is when a function remembers the variables around it even when that function is executed elsewhere.
>> Kyle Simpson: What do I mean by remember? I mean that a function that acts as a variable outside of itself.
[00:10:40] If you then take that function and you run it over here in some other entirely different lexical scope, it still has access to that variable from this scope. It can still update it, read from it, it still is a live linkage back to that variable, even though it's executing in a different scope.
[00:11:02] If you think about it, that maps to what those interview question responses I get are when somebody says, well it has something to do with an event handler. Well yeah, if you've written a click handler before, anybody ever written a click handler? And you put a function in your click handler, you probably referenced some variable, or object, or function from inside of that click handler that was in the scope where you set it up.
[00:11:27] But did you ever stop to wonder, when that click handler runs, it's running in an entirely different location. How does it still have access to the stuff that, actually that stuff we think, you know, conceptually, it should have been garbage collected long before now. But it didn't get garbage collected, it still has access to it and the answer to the question of, how is that possible?
[00:11:50] Closure is what keeps that access alive, it prevents things from being garbage collected. That otherwise would be garbage collected so that function maintains that linkage, that access to it no matter where it goes. When you write a function and you reference a variable outside in some outer scope.
[00:12:57] I remember writing PHP before they had closure and then I remember writing it after they had closure. And the major difference between the two was that all of a sudden in PHP that had closure functions were values that could be passed around. That was not the case before.
[00:13:14] Now they are values that can be passed around, if a function is a value and its lexically scoped you've got to have closure. It would make no sense, it would be nonsensical to have a function referencing a variable. In this location and it runs here fine but if you take and run it over here all of the sudden it's forgotten about that variable, that'd be nonsensical.
[00:13:38] So that's why I say closure is built into the very core of how our scope mechanisms and our functions as values work. Anytime you've done a click in or anytime you've done a set time out, anytime you've done an Ajax call and received a response back. All of those are scenarios where you virtually certainly were using closure to access stuff after the fact
>> Kyle Simpson: Instead of me telling you some brand new thing, it's a little bit more like Neo in the first Matrix movie. In the first Matrix movie, when Neo is gonna see the matrix or when he's revealed the matrix. When they show him the matrix for the first time, they're not showing him something that's brand new.
[00:14:21] They're showing him something that's been there the whole time, and he just couldn't observe it, that's what's happening here. You're seeing something that has been true of your program all along, and now you have a way to observe it when you think about a function that accesses a variable outside of itself.
[00:14:39] Here's one of those examples from earlier in our discussion. The unary utility, the thing that takes a function and makes a new function that's restricted, where's the closure here? Well, the closure's right there with the fn. We pass in an fn, we return back an inner function, this one's called one.
[00:15:00] And I want you to think about when that function from line 2 gets returned and we store that off in some variable like the variable g, for example. That g, if we run it at some point, when we run it, is it in fact not in a totally different scope than scope of the unary utility in line 1?
[00:15:21] When it runs, it's in a totally different scope nd yet, it still has access to that variable. How does it have access? Closure, you didn't have to do anything special. You just made an inner function, used a variable outside of itself. The closure came along for free.
>> Kyle Simpson: I want to put a little bug in the back of your mind here because we're gonna get more into this in a little bit.
[00:15:53] Do you think the unary utility is pure?
>> Kyle Simpson: Given the same function as an input, will it always produce the same wrapped function output?
>> Kyle Simpson: I have a high degree of confidence that the unary utility given the same input would produce the same kind of output. What about the output function itself?
[00:16:29] The function one, is that a pure function?
>> Kyle Simpson: It seems pretty straightforward, right? We're passing in an arg and passing that arg along to fn. The only way that fn could get redefined if it was redefined somewhere between line one and a half and line two and a half.
[00:16:53] Does everybody see that? Those are the only lines in the entire program that could possibly reassign fn. Fn is not actually a constant, we don't have the const keyword there but just by virtue of the way this code is written. It doesn't get reassigned does it? It's not even possible to reassign, so I ask again what's your level of confidence that the one function is gonna behave as a pure function?
>> Speaker 2: High.
>> Kyle Simpson: High degree of confidence.
>> Speaker 2: [LAUGH]
>> Kyle Simpson: Goodness, quiet folks today. I set you up for success, I told you the answer. High degree of confidence, that this function one will produce the same outputs, because nobody can redefine fn. Nobody does and nobody can that's a pretty high degree of confidence.
[00:17:54] So that was why it was important earlier for us to expand our definition of function purity to include the ability to reference something outside of ourselves. Because if functions to be pure couldn't reference anything outside of themselves, we couldn't use closure, could we? Do you see where I'm coming from here?
[00:18:15] Closure requires us using variable outside of ourselves. And closure is super important to functional programming Ergo we have to have a definition for function purity that accounts for using variables that are lexically outside.
>> Kyle Simpson: Otherwise closure would be inconsistent with functional programming principles, and there's a whole bunch of functional programming that would come crashing down.
[00:18:44] Most of it. Now, if on line one and a half there was something that did, you know, reassign fn or something like that, well then all of a sudden things get a little bit more interesting, right. All of a sudden we start to say I don't have as much confidence in the behavior anymore.
[00:19:04] So it's all about the context here, but this is a usage of closure which is entirely consistent with the principles of function purity. Here's another example. You remember compose write? Doing the same thing, now we're closing over two different variables, same principle applies. We're able to reference that fn1 and fn2 and this is safe, comp is reliably a pure function or will reliably behave as a pure function because nobody reassigns fn1 or fn2.
[00:19:38] If they did that could be a problem.