 Hey everybody, it's Brian. Welcome to the 12th Flutter tutorial. We're going to continue our journey on learning Dart. Now, one thing you should know is that we skipped something here. We went from control flow statements to classes and we skipped these exemptions and there's a reason why I did that. A lot of tutorials out there will talk about exemptions and say, exemptions are classes but we'll cover classes later, which means you are completely mystified and confused by exemptions the whole time. I wanted to reverse that and talk about classes first, that way during this tutorial, there should be zero misconceptions about what's going on under the hood and we can actually work with the advanced code rather than jumping back and forth. So, without further ado, exemptions, Dart provides an exemption and error types and there's a distinction between the two that you really need to understand here. So, the exemption class is basically it's information that we are conveying where the error class is an error object that represents the actual failure that we should have avoided. So, that's kind of the distinction between the two. And Dart has a little bit of, I shouldn't say a little bit, a couple predefined subtypes and you can actually build your own, which we're going to do in this tutorial. To do that, not just build your own but to just handle errors in general, you have to know how to throw errors and how to catch errors. Think of it like playing with a ball, you ever play, you know, with just like a baseball or football, it's a little kid, you throw it and catch it. You have to understand that program execution is very linear, meaning if at any time it breaks, your program will stop. I'm sure you've seen programs that have completely died. All right, so what we're going to do first is we're going to say we're going to catch an error. Now, usually when you catch something, it's not a great thing, right? So, we're going to say test A, oops, and then we're going to print and let's say we're going to do intentionally make an error here just because I want to show you what happens. Now, if you see this, you can tell that somebody ran out of coffee. There was some issue going on. Not only is this not even a variable, but it's undefined completely. We don't even have a test class in here anywhere. So, let's just run this and see what happens. First off, you can see the actual application is really trying to warn us, hey, bad things are going to happen if we do this. But if we actually just run it, you'll see that boom, whole thing just explodes and life as we know it has, you know, ceased to exist. No top level getter or setter tests declared. The entire application just hard crashed. We can look at the stack trace here and we can see, you know, tracing it back up to here. This is the reason why. No such method error. Now, that's a keyword right there, error. We were just talking about exemptions and errors and the error is the actual thing that happened. So, really what it's going on under the hood here is there is no such method. And that's, you know, kind of preceded by the error name here. So, that's the typical format for errors. You'll be able to see, you know, division by zero error, you know, catastrophic failure error, blah, blah, blah. There's any type of error you can imagine, but that's really the naming convention. And we're going to make a custom error. Before we do all that, we're going to actually learn how to catch these things. So, first thing we're going to do is I just want to print some things out here. This may look like this may look a little weird at first, but just trust me on this. Alright, so this probably looks a little bit crazy. We're going to go over this in depth because this is kind of the bread and butter of this tutorial here. And then we are just going to say done. So, we know this is going to crash because it's got the same code in here. What we're going to do is we're going to wrap it around what's called a try catch finally block. So, here's try, here's catch, and here's finally. These do three distinct things. Try will try to do something. For example, try to run a marathon, try to get a new job, try to find a wife or husband or whatever you're doing, try to bake a cake. Catch means that an error was thrown and we need to catch that. Think of it like a big fishing net. It's catching the problem. And then finally, finally does not care what happened up here, finally is just off doing its own thing saying, okay, I don't care what you two are doing. I want to do it my way. So, if you want to execute code and regardless of whether or not there was an error, you would put it down and finally. So, let's run this. You can see sure enough, starting trying error, no such method error, same error. And then we've got our error message with the rest of it and then tried calling test and then finally we're done. And you could actually just, you know, get this right here. So, we just don't care about that error. Error, don't care. So, we're just going to keep going on and our program finished with exit code zero, which means that it did not crash. It ran fully. It did exactly what we expected it to do and life is good. Some things you should know about this though. It is very bad programming to make what's called a silent error, meaning nothing happened here. Because if that error became catastrophic, it could potentially crash your program. So, it's always good to either log or let the user know or do something. That's why randomly, sometimes when you're using a program, you'll see a message saying error occurred, blah, blah, blah. And you're like, I don't care, leave me alone. I just want to do my work. But that's the programmer's way of telling you, hey, something under the hood went boom and you should be aware of this. So, that is how you catch an error. Now, we're going to actually raise an error. And this is actually a little funky if you've never done it before. All right. So, we're going to do our try catch block here. If you're wondering what this E is, the E is an automatic variable. It's actually a representation. It's the error class or the actual I'm sorry, not the error class, the exemption class that's in memory. And we're going to show how to build one of those here in a little bit. But right now, I just want to flesh this bad boy out. So, bear with me here. All right. So, we've got our try catch block in all of its glory. And we're just going to do some simple logic here. We're going to say if A not equal B, then throw, throws a special keyword. And then do, wow, that's bad when you misspelled do. I'm just, I'm still in a turkey coma. Yesterday was Thanksgiving and I'm just like not with it. All right. So, we're going to catch the error. And right now, this is what's called a silent exemption because we're not doing anything with this. So, we want to actually fix this problem here. Something went boom. And we want to just because actually print out our error message and print completer. Is that even a word? Completer. And let's actually just, while we're in here, fix the problem. We wasn't playing around when I said I was going to make a lot of errors in this tutorial. All right. So, we're going to, geez, there's even another one up here. All right. So, we're going to call this out and let's just comment this guy out here. So, we know that because those numbers are not equal, that it's going to throw this error. Now, if you look at that, you're going to stop and say, Brian, that's not even an exemption class. That's just a string. You're absolutely right. In Dart, you can throw any type of object you want. That will be, I think, under the hood, it gets wrapped into their exemption class and bundled up nicely and converted into a message. I think all it really needs is a two string function under the hood. All right. So, let's run this and find out what happens. And it says, something went boom, not the same. So, that is how you throw an error. Now, why would you want to ever create an error? I mean, why are you intentionally doing this? It's simple. Sometimes you want to know that something bad happened and you cannot continue execution. For example, let's say you're trying to open a file, but that file does not exist. You would throw a file not found exception or a file not found error and say, hey, boom, file not found, a big ugly message pops up on the screen and the user goes, oh crap, wrong file name. So, one thing you should also know is that you can actually cascade error messages. So, let's make a void internal and we're just going to say throw nope. Program just doesn't feel like working today. And in here, we are going to just call the internal. Now, let's see what happens here. Comment this out. Now, when we run this, boom, it crashed. So, we're calling outer, as you can see here, outer is calling internal. Internal actually throws the error. So, you don't actually have to catch the error where you're throwing it. That is where some tricky programming comes in, because you never know where an error is actually going to come from. So, that is how you would actually catch that program failed. What I'm getting at here is sometimes you'll use classes and libraries and things that other people have built. And if an error occurs or an error is thrown, you may have to actually catch those. So, you may not know that the error could potentially exist, but you're going to have to deal with it at some point. And that right there can get to some real headaches. And that's actually one of the biggest problems or biggest reasons why programs crash. It's you rely on somebody else's code, you're not fully comprehending what's going on under the hood, and then problems ensue. All right. So, let's just say we want to create our own error object here. So, we want to implement the exception class, and we want to just kind of flush this out. See a final string. I want a message. We're going to make this optional just because override this. Whoopsie. If I fingered that one. Very simple. I mean, very easy. You can make this extremely complex. We've had our conversation about classes and flow control, all that. You can do a whole lot of stuff in here, like maybe a custom thing you'd want to do is dump this to an error log. Maybe you would want to pipe it out to a website. Maybe you would want to take corrective action and fix something or pump something out to a database table. But for this example, because we haven't covered most of that, we're just going to make it very simple, very easy to work with. So, we have our color error. Close that. Close that. So, now we're going to import our color error. And we are going to make one horrendous, ugly looking piece of code here. Now, I did promise we would cover enum. So, let's actually, without further ado, here, whoops, we're going to make an enum and we're going to call it color. There's a reason why I didn't make an entire tutorial just on enums because they are just dead simple. So, an enum is basically a enumeration of something, enumeration of values. It's a zero based index. So, this is zero, one, two. And it's super simple to work with. And we're going to say void cats because I like cats. Then we're going to say color. Let's call this color. Notice how the upper and lower case are two distinct things. And we're going to say try. And then we're going to say catch. And finally, now here we're going to actually check. And we're going to say if color not equal color dot. And then notice here is our enumerated values. And the values is actually in there as a function, you can get a list of colors. We've talked about generic programming a little bit at a high level, it's going to be probably actually the next tutorial. But you can see how we have a list of colors, much like in the past we've had a list of strings or integers. So, if the cat is not black, then we're going to say throw new cat error. Why are you not picking that up here? Oops, it's not cat error. Jeez, color error. Told you Thanksgiving got me all messed up. Must be black because black cats are pretty awesome. Some people think they're bad luck, but I had black cat for years and years. He was probably the best cat I ever had. And then we are just going to leave it at that. We're going to say print. So, if we do a brown cat, why not? Everybody likes brown cats. Run this, you can see that unknown error must be black and probably would have done that. So, we can see that nothing really happened here. It's actually just pet the cat. Let's run this again. You can see how pet the cat never gets printed because we had the unknown error of must be black. Now, this is a problem. Why is this an unknown error? We actually know it's an error because, well, we threw it. So, what we're going to do here is we're going to add another called on. Oops, we're going to say on color error. And what we're doing here, whoops, we missed a little bit of verbiage here. We need to do something with that. So, on color error catch. There we go. We're going to catch the exemption. And then we're going to say print. You selected the wrong color. So, what we're really doing here is we're saying, hey, we want to know that Brian is horrible at spelling. We want to know what type of error. And so, you can actually create your own error types here using error classes. And let's actually make another error here just because, and we'll say cat. Hey, and we'll do our faithful little error here. There's no cat type. Therefore, we know it's going to be extremely explode here. And that would be a programming error anyways. So, you selected the wrong color. Let's actually make this black. Now our little program should work, meaning it should pet the cat. But then we've got this guy right here. Let's see what happens. Bang, suddenly we get an unknown error. So, that is a good example of a couple of things. A, how to use an enumeration or an enumerator. B, polymorphic programming. We see that this algorithm does two distinctly different things based on the input. And how to use custom error handling. It can get much, much more in depth than this. You can make just, you know, dozens and hundreds of these. Typically, what I do is I will write a function and then in every function, especially production quality code, will immediately be wrapped with a try-catch finally. And then I will put my specific error cases exactly how you see in this tutorial. That way, if I expect, you know, like file not found or disk space full or something like that, I know exactly what happened. And then I always have a catch all at the end. That way, if something completely out of left field happens, my program doesn't crash. It just says, hey, unknown error occurred. So, that in a nutshell is error handling. I hope you found this educational and entertaining. Be sure to check out my website voidrums.com for the source code for this and all other tutorials, but out in GitHub. In case you're wondering, I actually gotten quite a few questions about that. I put a lot of tutorials out here. And when you click the link, it actually puts them in as tutorials. So, I've got like cute Java, Python, Flutter, blah, blah, blah. If you just crack it open, you'll see the lessons are in there. These are all submodules. So, you can go right into the submodule and get the actual code. If there's no code, it'll just have a readme file. I try to keep it in there that way. I don't get the, hey, you're missing this. You're missing that. Last but surely not least, if this was even remotely helpful, feel free to donate and go out to the voidrums Facebook group. There are 1,700 other programmers out there that are willing to help you. That's it. Thanks for watching.