Functional-Light JavaScript, v3

Side Effects

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 "Side Effects" 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 explains why the causes of side effects are indirect inputs and outputs, and explains why they are unavoidable. Kyle also explains how they invalidate the properties of functional programming.


Transcript from the "Side Effects" Lesson

>> Kyle: How many of you have heard the term side effects before? Okay, so what we're getting at, what we're scratching at here is that in functional programming for there to be a function it's got to not have side effects. But what does that really mean? That word gets thrown around.

That term gets thrown around a lot. What do we really mean by that? Well, it's more than you realize. Number one, if I were to write a function called shippingRate, a procedure called shippingRate. Number one, right of the bat, you notice it doesn't have any parameters listed. And also you notice that it doesn't have a return keyword.

It does, however, still do a thing with some values. It takes a size, a weight, and a speed and it calculates a rate. So on line five, six, seven, and eight, we set up those inputs and output variable. We call shippingRate on line nine and on line ten, we legitimately got a shippingRate.

This code will work all day long. And this code actually is a lot like most of the code in most of our apps. It's using some other stuff around it and it's affecting somewhere something else, somewhere else in the program. And it accomplished our end goal, which is that it got us a shippingRate, which is fine as it's not a function.

>> Kyle: And you would say, well, you just told me on the previous slide that if there is a semantic relationship between inputs and outputs it's a function. Well yes, that's part of it but we have to keep evolving our definition. And that is a necessary component but it's not sufficient as a definition.

Because not only must there be a relationship between the inputs and the outputs, but the inputs and the outputs, to take advantage of the math that we're benefiting from with functional programming, the inputs and the outputs have to be direct. If the inputs or the outputs or both are indirect as they are here, then it's not a true function, even though there's a semantic relationship.

So when we say side effects, what we really mean is indirect inputs or indirect outputs, or both. Some people like to call indirect input side causes, because it's like cause and effect. Maybe that's useful. I like to use the big umbrella term side effects. Side effects are both side causes, side indirect inputs, and potentially indirect outputs affecting things outside of yourself.

You'll have to trust me and I can't even really explain to the math, but the math doesn't work if any of the inputs or any of the outputs are indirect, it just doesn't work. So in a sense, we could twist the rubix cube around and we could say, well, its got to take direct inputs, aka arguments past the parameters.

And it's got to compute and return a value without assigning to anything outside of itself. It can't access anything outside of itself and it can't assign to anything outside of itself. That's a clear and solid way for us to avoid the whole side effect of thing, and that should make it a function.

Close, we're getting closer. Those are necessary components, but they're not sufficient. This is side effects. And we want to avoid side effects, because side effects invalidate the idea of functions. We don't get functions and therefore we don't get the benefits. And by getting the benefits, I don't mean that we can't use the API's.

We can definitely use the API's. What we don't get as we don't get the prove ability. We don't get the verification, the security of knowing that this thing is definitely gonna do what we want it to do. It's kind of a waste of time to go through all the motions as if you're doing functional programming and not get the real benefit out of it.

And not only you don't get the benefit, but your readers don't get the benefit either.
>> Kyle: So that's why when we make shippingRate and we pass in the inputs and return an output. We call shippingRate with some inputs and we assigned in this case to the rate variable, the output that's direct input semantically related to direct output.

And that's a function.
>> Kyle: But I want you to notice something that's interesting. And by the way what I'm about to say, I can only speak to JavaScript since that's the context of our discussion. I'm not saying anything about functional programming in a general big sense. But I am gonna tell you that in JavaScript, this much I can say, there's no such thing as a function, there's such a thing as a function call.

That for us to have the definition of a function isn't the important part. The important part is that, that function was called on line seven and gave direct inputs and got a direct input at that output at that call, that's the important part. It is the function call that matters.

It is the characteristics of that function call that matter. Are there direct inputs and direct output from this function call? That's the question. Our temptation is to look at the definition of the function to try to answer that question. But it turns out because of the nature of how JavaScript works we cannot fully answer the question, is it a function, without looking at the function call.

So the important thing to talking about a function and whether it is behaving as a function or rather behaving as a procedure, the important characteristic there is not the definition of the function but the call. The call needs to avoid creating or using side effects. And it sort of indirect that the definition of the function is that way.

Our temptation is to think about the function being, but it's the call. We wanna avoid those side effects with the function calls rather than with procedure calls, so we use function calls to avoid side effects. But that's only if possible, because not all side effects will be avoidable and that's what we wanna jump into.

So let's talk about side effects. What really are the side effects that we need to be concerned about? We saw one kind of them which is variables outside of the function, but there's more to it than that. It's more than just a variable. For example, any sort of IO, printing to the console, reading or writing from the file system, any of those IO kinds of things input, output.

Those are all side effects on the system. So functional programming says avoid it, those are out. Database Storage, that's a side effect. Functional programming says that's out. Network calls, reading and writing from the DOM, timestamps generating the timestamp. That's a side effect. Generating a random number, that's a side effect.

So all of a sudden we start to think, wow, that's a lot of things in our program that are side effects. And functional programming seems to say we have to cut all of those things out. But the fact of the matter is you can't cut all of these things out, because even if you think about it in a theoretical sense.

Any program that runs is gonna produce heat by the CPU and that is the side effect that is an observable change to the state of the system. As a matter of fact, not even just the heat of CPU just the observable delay in time where one program can't run because another program is currently running, that's a side effect.

Not only is it practically impossible to avoid all side effects, it's also theoretically impossible to avoid them. So when we say avoid side effects, what we're really saying is minimize side effects. Have as few side effects as possible, knowing full well that you have to have some side effects.

A program that had no side effects which can't even exist, but if it could exist, a program with no side effects would be indistinguishable from the absence of that program. You couldn't even prove it existed. You couldn't send anything into it and see anything come out of it, so you couldn't even prove that it existed or that it ran.

So we really wanna change our mindset from side effects are bad to side effects take away the benefits of why I'm doing functional programming in the first place. They reduce, they water down, they impurify the benefits of functional programming. And that's why if we are going to do side effects, which we have to sometimes, we wanna make sure that they are very obvious.

We wanna make sure that we are very intentional about them, rather than simply not caring about side effects at all.
>> Kyle: So there really is no such thing as no side effects, it's just that we want to avoid them where possible. And when we have to do them, make them super obvious.

Why do you think it would be important for us to make them obvious? Well, let's think it back to what I said in the outset of our course. We said that, code that is written with functional principles is based upon mathematics, right? And just like we don't have to prove to ourselves 1 + 1 equals 2.

if you have a set of your code that is written with functional principle and then you have a bug in your program. And you could have the bug in your functional part or it could be in the parts that don't abide by functional principles. Where is it far more likely that the bug is?

It's in the place where your side effects are. I love the way a functional programmer describes this, they will describe this idea that we collect all of our functional programming stuff, all of our pure functions as they're called and we'll get into that in a moment. We collect all of that stuff together and what we would visualize is a sphere, it's the core that is functional.

And then we collect all of the side effects. All of the non-pure stuff on the outer shell. We make a clear delineation in our program. I've gone so far, this sounds silly, but I've gone so far to make a file called sideeffects.js and put all my side effects in that one file.

Because if there's a bug, it is vastly more likely that it's where my side effects are than not. It's more likely that I got one plus one equals two correct. And then I mess something else up with not now. I got an algorithm wrong or I used the side effect wrong, something mutated in a way I wasn't expecting.

That's where bugs more likely come.

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