We just saw map, which is a transformation operator. There are a couple of categories of operators, such as transformation, but also filtering, combination filtering, etc.
One of these categories is the utility operators. The most important utility operator is do. Do is very similar to map. It also takes a function, but it does this. You get that X as an input, but you don't need to return anything. Actually, if you do return, then that return will simply be ignored.
Inside here, you can do, for instance, a console log outputting that, and if you return anything, that will just be ignored. Do is actually similar, or equivalent, actually, to foo.mapped, where this function X will simply immediately return X, but it will also on the side run that console log for you.
Do is just a special case of map, where you are returning the same value that you received. In case we return 10 here, do will just ignore what you did, and it will anyway return X.
What is the point of having do if it's actually not transforming that value at all, it's just returning the same value? Do is really useful for debugging purposes. You can do something like this, you can apply do, take that X value, and you can put in console log something like before, and that value. That will return you an observable that looks like the same thing, because it just returns the same X value.
Then we can call map, and after we have that mapped observable we can run again do, which will give us the same observable as this input here, like that. But here, we can say after. Before and after will tell us what was the value before we called map, and what was the value that came out of map.
If we write our code like our marble diagrams, we're going to have X, which we'll call the console log, saying before. We're returning this, but this will be anyway ignored by the do, and it will anyway return X. That's the idea.
Then we also do the map to multiply by two. Then we run again do with an after. Now this is bar as an observable, and if we run this, we're going to see before and after being called between this map. Then you can see clearly that before calling map, the value was one. After calling map, the value was two.
Now, it's important to notice that do does not trigger a subscription. That's important because do is not supposed to call or trigger anything to happen. It simply exists as a spy in order to inspect what happened.
Remember, a subscription means giving values, but do doesn't mean that. Do operator means if the observable source delivers values, then please silently run also this function on the side.
In fact, if I comment this out, none of these console logs will be called. That's important to remember, because do is in the subscription chain. It means that once we subscribe to bar, then this will be subscribed and that will be subscribed, and that will be subscribed, and this is how these will be run.
That's why do is a great tool to use for replacing console log, for debugging, and we may use them in upcoming lessons to inspect the behavior of other operators, especially in this fashion where we put dos as a sandwich here around the operator that we want to understand.