Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

2.5 A Look at Pure Functions

In this lesson we take a brief detour from our project in order to explain what a “pure function” is and why it’s so important to functional programming. At the end we’ll apply this concept by purifying a few of our existing functions.

Related Links

2.5 A Look at Pure Functions

In this video, I'm gonna talk, for just a few minutes, on the idea of pure functions and side effects. We're gonna start by looking at an example of a pure function. I'm gonna jump over here to JS Bin, to show you. I've actually already got a bin set up for this. Let me just put the URL in here. Explain what's happening here. So let me show you the HTML. Some very simple HTMl with two divs. I have a class of box, and this data-expand attribute, which is set a value, one is 100, one is 200. The CSS is just on the .box, it sets them at 20 pixels each. Grey with a little transition. So you can see our Java Script is running with no functions at all right now. So this might be how you would first set it up. Now you just grab a copy of all the boxes using querySelectorAll, and then you loop over them. And for each of them, you grab their expand value, concatenate px on the end, and then set the height and width to that new value. Now because we've done it like this, we actually are showing the expanded values by default. So if we want to make this clickable, or if we want to make it more declarative, like we've done in the past, we need to make a function. So let me show you what a first pass at a function might be. Let's change this to the second copy here, and you'll see a function called expandBoxes. So now you can see this is working a little differently. We are waiting for a click to happen. And the way it works now is, any click on the body will actually expand all the boxes. It'll call this expandBoxes function. And it's gonna do exactly what we did before, it sets the expand variable, or initializes it, loops over the boxes, and sets each one. Now this function here, let's just demonstrate this works. So we'll click in the middle of them, and they'll both expand. If we run with JS, it'll reset it, and I can click on either one, and they'll both expand as well. So this function here is not a pure function. It's not a pure function for a number of reasons. One, it relies on other values outside of itself. So a pure function would get all the values it needs from the parameters that are passed to it. We're not passing any parameters here. So it goes and finds boxes in the scope, but not in the function. So it's right here, in the scope, but we have to assume it's there. Then we loop over them, and then we're setting values that were not part of this function. So this is called side effects. We're actually doing work that's not related to this function, and we're just setting values. And so that can get you into trouble if you have a lot of functions that all have side effects, cuz they'll start overlapping on each other. And the last thing that makes this not a pure function is the fact that it doesn't return anything. And that is a bad thing because it tells you, right away, that this function is designed to have side effects, like we just talked about. If it was not going to have side effects, it would return a value for you to do something with later. Since we're not even, pretending to do that, we don't even have a return value, it's a pretty obvious red flag that this function is only around for side effects. Now you'll need some of these, but you want to be careful of having them all be like this. You want to try to make functions that are pure. So let's take a look at what pure functions could be. So here's an example of a little bit of a different situation, okay? So now we have this onClick method, and we grab the element that was actually clicked, so we're not just running a function to expand all the boxes. We want to actually expand the box that was clicked on. And so, we use e.target to find the one that was clicked. And then, we look in its class list, and see if it contains the box class, cuz if you click in the middle here, we don't want to do anything. And then we'll expand the element, and pass it the clicked value. Okay, so expand element is a function. Now this function is also not pure, because it has side effects. But like I said, side effects are important. You, you have to have side effects at some point, otherwise your app doesn't do anything. So having side effects isn't bad, we just want to limit how many things have side effects. So one nice thing about this function is it actually accepts a value, so it's not relying on global variables set somewhere else, it takes in the value, element. It then sets the height to getExpandedValue. And actually, this is wrong, it's not gonna work. I'm actually gonna make this element. So we pass in the element to getExpandedValue here, and this function is actually pure because it takes in the element, and then it returns the dataset.expand value, concatenated with the px, for pixels. So this is exactly what we'll need to set the height and the width in expandElement, so that we can do our expansion per click. So now if I click in the middle here, nothing happens. But if I click on one of the elements, it expands. Now if you click the other one, it also expands. So the expansion is less important than understanding that this function, right here, is a pure function. It takes in a value, it doesn't have any side effects, it doesn't set any values on other objects, doesn't try to tap into the DOM, and do things. It just takes a value, and returns a modified value. So what does this mean for us? Not too much. The one place I think we can clean up is this filterBeers. Right now, it assumes that it has access to this beers array, that's already in the global scope. So if we took this function away, and moved it somewhere else, it would fail, because we would not, it wouldn't have the beers function, or the beers variable available to it. We'd have to pass that, we'd have to move that along with it, and we don't want to do that. So we're just going to make sure that we require a list of beers right here. So where are we calling filterBeers? So right here, our makeFilter function probably needs to have beers passed into it as well. So that we can, when we call filterBeers, pass those in. So now here is makeFilter. Here's where we're a little more imperative, so we can actually pass the beers. And so, again, to deal with confusion here, I want to change this to allBeers, so that we know which one is coming from the outer scope, and which one's passed in. So right here, we're loading all the beers. That's what we're, see, that's why that was confusing. Here we want to pass in allBeers. Same here. And, as well, right here. And now we're being much more explicit. We had to write a little bit more code, but we're being more explicit, while still being declarative and functional. And now this makeFilter function, as well as this filterBeers function, are both pure. Let's close the console and just make sure this still works. All the beers there. Let's run through all of our filters, and we're all set. So that's a quick overview of pure functions, and getting rid of side effects, which are both key parts of being functional in your programming style. In the next video we're gonna jump in, to start creating some functional utilities, to actually add some functionality to this website

Back to the top