[MUSIC] Alright, so so today's lecture is about the debugging tools that are built into R. So these come with R. They're not part of any package and they can be useful for kind of figuring anything out, figuring out what's wrong after you've discovered there's a problem, right. So how do you know that there's a problem? So, there are a couple of indications that R, will produce that that will give you the sense that there's something going on. And they kind of, and this is the, roughly the gradient. And so I think I mentioned this before. But, basically there are three main types of indications. The first is a message. And a message is a very tame notification. It's just an in, it could be a diagnostic message that something happened. But it could, it could be nothing. Okay? And and so the message won't stop your function from executing. It will just it will print. There will be a message that gets printed to the screen and the execution of the function will continue and that's all. The next level up is the warning. All right? So the warning is another indication. Usually, if you're writing a function, you are choosing, you're trying to figure out, okay, what's a message and what's a warning. furthermore, or if you're using a function and you're figuring out well what does that mean, a warning is an indication that something unexpected happened it's not necessarily a problem, and may, and many times you, you, you explicitly want to ignore warnings but there's something unexpected happened. So the function was expecting one thing, and it got something slightly different. It wasn't enough to kill the whole thing, But it was enough to kind of trigger this warning. So execution of the function will continue if a warning occurs but you'll get a message after the end, so once you'll get a message when the function completes execution. So when the function comes back, when you get your console back, that's when the warning appears. So you won't get a warning in the middle of the execution. By default. So this is, these are generated by the warning function, sorry I should say the messages are generated by the message function. And then an error is the last stop, right? So an error is a fatal problem. This stops execution of the function. And and these, and error messages are produced by the stop function. So and then there's a general notion of a condition. Which is it's the higher level concept. It can, all three of these things are, are conditions. And so you can, you can imagine that, and so it, you can create new conditions if you wanted to. So if you have, and generally you're not going to be doing this at this level but if you have a, a, another type of of, condition that you want to, kind of trigger when something, when a special thing happens. So it's not an error, it's not a warning, and it's not a message. You can create your own conditions and and using some of the functions that are available. So we won't be doing that now, but there is this notion of a condition and it's, it's generic. So this is your basic warning, right? You take the log of a negative number. You can't do that, right? Now notice that you get a value back. It's a NaN, right? Not a number. And, but you also get this warning which occurred after the execution of the function. And it just says that in the log of minus 1 NaNs are produced, right? So this is your typical and, and sometimes that's fine. Because maybe you're taking a log of a bunch of numbers and maybe some of them are negative, but you don't really care and then you're going to make some sort of plot or something like that. So so this is the kind of thing where you probably wouldn't want the function's behavior to just stop anytime it sees a negative number because sometimes these things just happen. You get negative numbers on occasion and you want to take the log anyway. So so that's a warning. Now I've got a little function here that I've created. It's very simple it takes your input. It checks to see if it's greater than zero. If it's greater than zero, it prints a message saying x is greater than zero. [COUGH] If it's less than or equal to zero, you get a message saying that it's less than or equal to zero. So very handy function I'm, I'm sure you'll all be using soon. and, and then last I want to mention this part here. So invisible is a function that that, that stops or I should say prevents auto printing. So normally when you, if I if I'm at command line and I type a function, remember the, and I execute a function the, the function will return the last element of, that's in its function body, right? So if the last sum in this function body is like is numeric vector, it will return that numeric vector. Now what happens is that if you just execute the function, that numeric venture, vector will be automatically printed to the console because it got returned by the function and R will use auto printing to just print that to the console. If I call invisible on the return object, then it will still return the same object but it won't, it wont do the auto printing. So you can call the function and the object will be returned. But there won't be any auto printing. So a, a, a, a, an example of a function like this is the load function. So we haven't really used that much, but the load functions loads objects from what, from a saved work space, so it's like the opposite of of save, right? and, but when, and when it loads the objects, it actually returns a character vector containing the names of all the objects that it loads. But that doesn't get printed to the screen and because, it's, it's returned invisibly. Okay. So if you have a function that returns something invisibly then the return, what happens is that the object that gets, that gets returned by that function doesn't get printed to the console and so sometimes you want that to happen and sometimes you don't. Sometimes it doesn't matter. So here I've, I've just added this here just so I can, you know, tell you about it. It's not particularly important. But actually, the print, actually I should say that any print function here actually all print functions will return the string that it prints. Okay. So when you say print X, what gets returned is a string, X. Right? But you don't actually see that, because it, the, the, the, the return value is, is, is returned invisibly. Right? So it actually. So, so, so, so you could assign the output of print to, like, an, an object. But you. Generally speaking, you never do that. So, anyway. That was a little diversion on invisible. So here I, I create my printmessage function, and I call printmessage(1), great. No problem. I get the message x is greater than 0. Okay. So and so what does printmessage return, just before I go on? Printmessage returns its argument, alright. And so actually, if I had assigned print, the output or printmessage to some other object, it would be the number one in this case, right. Even though it didn't printout the number one anywhere. So now, I'm going to pass it directly an NA, right. And and, and we're going to get an error here because you can't make the comparison if NA was greater than zero, it's not defined, right. And so it doesn't know what to do it can't move on. It, and so it has to error out. Okay, so you get an error saying that in this expression if X is greater than zero the missing value, you, you have a missing value where, so it was expecting true or false and instead it got NA, which is neither true or, nor false. Right, okay. So something happened there that's wrong. Now, I'm going to to fixed this problem so to speak. I've got a new function print message two and the first thing we are going to do is I'm going to check to see if the argument is NA, right? So, now I if it's NA, I'm going to print this message, right. So it's not going to produce an error, it's just going to print, print a different message. So this function's going to print one of three messages for now and then it's going to return its argument, invisibly. So when I call this, so now what, so what's something that might typically happen? Well I, I calculate the log of minus 1 and I assign it to X. So that doesn't stop anything. I just get a warning, and I move on, all right? Now I'm going to printmessage on x, and I'm getting x as a missing value, right? So, now that, now there's no error there but it's, it may be unexpected, right? Because maybe I, I, I, maybe I thought that, okay, well the thing that I'm inputting into printmessage2 is, is like some positive number, so I thought I was going to get the message X is greater than zero. But instead I'm getting this message x is a missing value. So what happened right? So um,this is the kind of thing where where what you thought you were going to get, where your expectation is different from actually kind of what the function produced, right? And so all I'm trying to say here is how do you know when something's gone wrong, right? And sometimes it's easy to tell like in the case where you got the error message. But sometimes it's not easy to tell because here there's no error but it's not exactly what it, what I was expecting, okay. It's when you, when you're looking at a function, you think something's gone wrong, there's a couple questions you want to ask yourself. To see whether there something actually is wrong, or maybe, or is there is something we call user error, okay? So what was your, so the thing about when you're kind of thinking about, when you're debugging a function you want to answer all these questions as you're going through your process here. So what was the input that you put? What, what did you feed into that function? Okay, not what you thought you fed into that function, what did you actually into that function? Okay, so I thought I fed that function a positive number but in reality I fed it a, a NaN. Alright, so how did you call the function? What are were the arguments that you gave? Things like that. What were you expecting? So you, and this is important when you're asking someone for help, or you're asking someone a question. I can't just, it's not that useful to say oh the printmessage2 to function didn't work. How do you know it didn't work, alright? Because, and then you say, well I was expecting this, but I got that, okay? That's how you know it doesn't work. And then, someone could say, well you shouldn't have expected this, because that's not what that function does, or you know, or something like that. But or you can say, okay, here's the problem. So what were you were expecting is then very important to be able to articulate at least to yourself and maybe to other people. What was the output that you were expecting, were the were you expecting some message that you didn't get? Or other results, other numerical results, things like that. So what we're expecting, and then of course, what did you actually get? How do, how did what you actually get differ from what you're expecting? And then of course were expectations correct in the first place? So, if you were expecting something that was, that was in fact incorrect then your notion of what is correct and incorrect is now being challenged, right? So an important, and another key aspect of debugging of course is you have to be able to reproduce the problem, right? Because if you can never reproduce the problem, you'll never have a chance in figuring it what went wrong, because it only happened that one time, right? So this is very, very, very, very important. And unless it's a very I mean unless it's like the most basic problem. And I can't even say what that would be. You have to be able to reproduce the problem. You know, because you have to be able to show someone this is how I created the problem. Because most people are not going to know if you just show them the output of the error message, or what that means, or where it came from or how you got there. Okay, so the process by which you encounter the error or the problem is very important. So you, you have to know how to reproduce the problem. There are some problems, and so when I was talking about, for example, when in random number generation you need to set the seed because it may be that only under a certain sequence of random numbers that a problem occurs. And, if you're not setting the seed, you will never be able to reproduce that problem, because every time you run it, it's going to be a different set of random numbers. There are other types of problems that can be hard to reproduce. They, and, but they're more complex. They're usually, for example, if you're writing networking co, networking functions, you know, something, so you're doing like parallel programming, often, those kinds of problems can be very hard to reproduce because they depend on activity in other machines and things like that. You can't really reproduce that. Things that, if you're getting code over the internet, and so if you're getting data over the internet, and your code is kind of interacting with things in the web, that can, problems there can sometimes be hard to reproduce because servers on the other side may change or whatever. And so you, you can't always freeze things in time. If it's something that's just happening on your computer it's usually going to be easier to reproduce the problems. so, unless, I mean only under very esoteric circumstances, circumstances will it be hard to reproduce a problem on your computer.