Functional-Light JavaScript, v3

Closure Solution

Kyle Simpson

Kyle Simpson

You Don't Know JS
Functional-Light JavaScript, v3

Check out a free preview of the full Functional-Light JavaScript, v3 course

The "Closure Solution" Lesson is part of the full, Functional-Light JavaScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle live codes the solution to the exercise.


Transcript from the "Closure Solution" Lesson

>> Kyle Simpson: Let's talk about the solution to our exercise on closure. Now I am just gonna forewarn you, I'm going to deliberately solve this incorrectly to prove a point about the way that we think about closure and what it means for functional programming, and then we're gonna solve it the correct way.

So the first thing to note is that strBuilder when called with a string, returns back what?
>> Kyle Simpson: Returns back another function that's expecting to be called with another string. So it's gonna keep returning back a function, and it would do that essentially forever. As long as you keep passing in strings, even empty strings, it's just gonna keep returning back a function.

So what does that pattern look like? Well, we know at a minimum, we've got to make and return a function. So I'm gonna just call this function next because it's just sitting there waiting for the next string, next string, next string, okay? That function is going to receive a string.

Well, it's gonna receive a value, we're not sure if it's a string, it's gonna receive a value. Now, I want to keep going, if you will, in other words, I wanna return a function if the value that was passed in was a string, keep going as long as it's a string.

As soon as it becomes not a string, that's when I wanna bail out, okay? But I need to keep track of the strings that I have seen so far cuz I'm gonna keep returning this thing back over and over and over again. I wanna keep track of those strings in some way, and it seems natural that I might just start concatenating it on to the string.

So if I receive value and it's, oops, if I receive a value that is of type string,
>> Kyle Simpson: Then what I know is that I could just concatenate it on to the end of str, right? Cuz that was my initial string. And then I can just start concatenating stuff onto the end of it as I see it until I don't see a string and then just I need to return string, that's a convenient way of keeping track of it.

So if I just said str += v. And then otherwise, in other words, so if it was a string and I concatenate it on, what do I wanna do? I wanna return that next function again, just the function itself next, so that I just keep returning a function back until I pass in something that's not a string.

And that's my signal to return whatever is in str. Did you follow that thought process that I went through there? I need somewhere to store all those values, and it seems logical that I just throw them onto the end of the string and that'll be a good place to store them.

And how do I know if I need to keep going with a new function or not? It's whether I passed in a string or not. Everybody with me? Now if I take this code, this is deliberately the wrong solution and I'll explain why in a moment, but if I take this code and we try to run it, we'll notice that I get several failed tests.

But notice something interesting, the tests that did succeed is the most, seemingly complex of the test. It's the one that was called a bunch of times, that one passed, and it's all these ones that didn't pass. And there's a clue there, if you're paying close attention, there's a clue there as to why our solution didn't work.

And the clue is that what we have are these intermediary functions. Notice I've got Kyle and Susan. Those are sort of a fork, if you will, from hello where we're gonna end up with hello Kyle and hello Susan. But if I have modified string with the word Kyle and then I try to call Susan, if this function is close over that the same string and our modified string, that string no longer says hello.

Now, it says hello Kyle, and I'm trying to put Susan on to the end of hello Kyle. You follow me? So that's really kind of where our problem is stemming, is that if you think about it, what we're doing is we're closing over a variable that's being modified each time.

So in other words, we have functional impurity here and that's why this is not working, it's because we have functional impurity. So I'm gonna go back and try to solve this in a different way that preserves the functional purity, okay? So let's start over. Well, I'll leave the function next part but let's rewrite this part.

So we know now that we never want string to be modified. If we're closing over this thing, which is what this inner function will be doing, we wanna only close over string that stays the same, okay? So I do still wanna do a test. I wanna say if the type of v is string, then I wanna do something, and I am going to return something here, so we'll do that.

If I don't return a string, then what is it that I want to return? Now this is the part that's maybe gonna be a little bit counterintuitive to you. Let's talk about what happens if the string, we need to figure out what we're putting here. Let's talk about what happens if we have passed in a v that is a string.

We have str, whatever value it currently has, and we have v. We don't wanna modify string but what we want is a new function that will wait for the next string, and that new function needs to know about both string and v. So, in other words, what I really wanna do is I wanna call string builder again, I wanna actually call it not return it.

Now when I call string builder, what is it gonna return to me? It's gonna return me another function. But when I pass in the string builder is that, it's the new partially concatenated string each time. So I'm not modifying a variable that I'm closing over, I am calling to the next level.

So this is almost recursion, it's not exactly recursion, but when string builder comes back in, this string is now gonna be the two strings, and we're closed over the two strings. And if we do it again, now it's a bigger string and we're closing over a bigger and bigger sting, but every single level of that closure is only ever closing over one value, it never mutates itself within the closure.

So what if I didn't get a v? Well, now, I just return string. If v wasn't a string, in other words, it was undefined or false or something like that, it wasn't a string, then I know that whatever this was last time was the end value of our string and I should just return it.

>> Kyle Simpson: Let's test myself to make sure I didn't make a mistake here.
>> Kyle Simpson: And now all of our tests passed, okay? So the key takeaway here is that if you're going to use closure in functional programming, you have to make sure you're closing over non-changing, non-mutating values. As soon as you start mutating values that you closed over, you lose your functional purity.

And it won't often be a catastrophic test failure like I set up, it'll often be an extremely subtle bug that only comes up once every million requests, that'll be what you're facing, okay? So one of the takeaways that I'm hoping that you're getting from this course is that if we code using these functional principles, we actually avoid entire classes of bugs that could have happened otherwise.

They're just not even possible to happen because of the principles of functional programming being so sound mathematically. So if we close over an ever changing values, we're far less likely to have one of those bizarre strange cases.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now