Changing Equality in C# - Overloading == and Overriding Equals()
Read full transcript 23 segments
-
You can change how equality works in C, You can change how equality works in C, but is it a good idea? In this video, but is it a good idea? In this video, but is it a good idea? In this video, I'm going to show you how to overload I'm going to show you how to overload I'm going to show you how to overload the double equals and how to override the double equals and how to override the double equals and how to override the equals method. Then I'm going to the equals method. Then I'm going to the equals method. Then I'm going to show you what it breaks when you do that show you what it breaks when you do that show you what it breaks when you do that and how to fix it. Now, if you don't and how to fix it. Now, if you don't and how to fix it. Now, if you don't know me, my name is Tim Corey and I help know me, my name is Tim Corey and I help know me, my name is Tim Corey and I help people become better developers, people become better developers, people become better developers, especially around C and .NET topics. I especially around C and .NET topics. I especially around C and .NET topics. I have over a thousand videos here on this have over a thousand videos here on this have over a thousand videos here on this channel to help you on your journey. And channel to help you on your journey. And channel to help you on your journey. And if you're looking for more specific if you're looking for more specific if you're looking for more specific courses or larger topics, then go to courses or larger topics, then go to courses or larger topics, then go to devforge.com where I have a ton of devforge.com where I have a ton of devforge.com where I have a ton of courses there that the funds from courses there that the funds from courses there that the funds from support more free content like this. So support more free content like this. So support more free content like this. So definitely check it out. There's also definitely check it out. There's also definitely check it out. There's also more free content on devforge.com. So go more free content on devforge.com. So go more free content on devforge.com. So go check it out. Okay, we're going to work check it out. Okay, we're going to work check it out. Okay, we're going to work on changing equality in C. And I've on changing equality in C. And I've on changing equality in C. And I've already written some code. Um, by the already written some code. Um, by the already written some code. Um, by the way, this is kind of based upon three way, this is kind of based upon three way, this is kind of based upon three previous videos. So, I just did a video previous videos. So, I just did a video previous videos. So, I just did a video last week about equality. So, if you're last week about equality. So, if you're last week about equality. So, if you're thinking this is deja vu, well, no, this thinking this is deja vu, well, no, this thinking this is deja vu, well, no, this is the next step in that equality, which is the next step in that equality, which is the next step in that equality, which is how to change the equality. Um, but is how to change the equality. Um, but is how to change the equality. Um, but we also need to know about specifically we also need to know about specifically we also need to know about specifically value types versus reference types. And value types versus reference types. And value types versus reference types. And you know, the garbage collection video you know, the garbage collection video you know, the garbage collection video kind of covered a couple of topics that kind of covered a couple of topics that kind of covered a couple of topics that might be helpful as well. So, definitely might be helpful as well. So, definitely might be helpful as well. So, definitely check those out. I cover a lot of check those out. I cover a lot of check those out. I cover a lot of content here on this YouTube channel.
-
content here on this YouTube channel. content here on this YouTube channel. Um, and those those three especially Um, and those those three especially Um, and those those three especially going to be really helpful um in making going to be really helpful um in making going to be really helpful um in making sure that you are up to speed on where sure that you are up to speed on where sure that you are up to speed on where we're at. Now, if you haven't watched we're at. Now, if you haven't watched we're at. Now, if you haven't watched any of those, I think you'll still be any of those, I think you'll still be any of those, I think you'll still be fine, but I want to make sure that um fine, but I want to make sure that um fine, but I want to make sure that um you know, you at least have the best you know, you at least have the best you know, you at least have the best opportunity to understand this topic. opportunity to understand this topic. opportunity to understand this topic. Okay. So what I've done here is I've Okay. So what I've done here is I've Okay. So what I've done here is I've created a class. Now this class has created a class. Now this class has created a class. Now this class has first name and last name. They're both first name and last name. They're both first name and last name. They're both nullable. I have created this nullable. I have created this nullable. I have created this constructor um in order to just speed up constructor um in order to just speed up constructor um in order to just speed up the the instantiation of those classes. the the instantiation of those classes. the the instantiation of those classes. I've created four instances of a class I've created four instances of a class I've created four instances of a class Tim Corey, Soustorm, Bob Smith, and Tim Tim Corey, Soustorm, Bob Smith, and Tim Tim Corey, Soustorm, Bob Smith, and Tim Smith. And then I create a dictionary Smith. And then I create a dictionary Smith. And then I create a dictionary with the key of person model and the with the key of person model and the with the key of person model and the value of int. This is kind of throwaway value of int. This is kind of throwaway value of int. This is kind of throwaway dictionary. Who cares? U and it's count dictionary. Who cares? U and it's count dictionary. Who cares? U and it's count by person. So 5 94 and one for the four by person. So 5 94 and one for the four by person. So 5 94 and one for the four objects. What these numbers matter? They objects. What these numbers matter? They objects. What these numbers matter? They don't. Um they're just there as hey can don't. Um they're just there as hey can don't. Um they're just there as hey can you find the right value compared to the you find the right value compared to the you find the right value compared to the person model? Now the way the dictionary person model? Now the way the dictionary person model? Now the way the dictionary works you might think is it goes oh is works you might think is it goes oh is works you might think is it goes oh is the person model you're passing in equal the person model you're passing in equal the person model you're passing in equal to P1? If not is it equal to P2? Is it to P1? If not is it equal to P2? Is it to P1? If not is it equal to P2? Is it equal to P3? Is it equal to P4? That's equal to P3? Is it equal to P4? That's equal to P3? Is it equal to P4? That's not how it happens. We're going to not how it happens. We're going to not how it happens. We're going to understand why in just a minute, but understand why in just a minute, but understand why in just a minute, but let's start off with the basics. Are P1 let's start off with the basics. Are P1 let's start off with the basics. Are P1 and P4 equal? Well, P1 is Tim Corey and and P4 equal? Well, P1 is Tim Corey and and P4 equal? Well, P1 is Tim Corey and P4 is Tim Smith. And even if they said P4 is Tim Smith. And even if they said P4 is Tim Smith. And even if they said Tim Corey for the last one, they would
-
Tim Corey for the last one, they would Tim Corey for the last one, they would not be equal because they're in not be equal because they're in not be equal because they're in different memory registers. This is a a different memory registers. This is a a different memory registers. This is a a reference comparison. But we're going to reference comparison. But we're going to reference comparison. But we're going to see that just to be just be clear. And see that just to be just be clear. And see that just to be just be clear. And then is P4 in the dictionary? And if so, then is P4 in the dictionary? And if so, then is P4 in the dictionary? And if so, what's the value? We're going to look up what's the value? We're going to look up what's the value? We're going to look up in that dictionary what the value of P4 in that dictionary what the value of P4 in that dictionary what the value of P4 is. That should be one. Let's just run is. That should be one. Let's just run is. That should be one. Let's just run this just to make sure it works. Uh, this just to make sure it works. Uh, this just to make sure it works. Uh, false. The the two references are not false. The the two references are not false. The the two references are not this equal reference. That's that's what this equal reference. That's that's what this equal reference. That's that's what we expect. And then P4 is in the we expect. And then P4 is in the we expect. And then P4 is in the dictionary and it value is one. So, so dictionary and it value is one. So, so dictionary and it value is one. So, so far we've got a working application. far we've got a working application. far we've got a working application. We're going to break that. We're going to break that. We're going to break that. And the first way we're going to do that And the first way we're going to do that And the first way we're going to do that is we're going to get this bright idea is we're going to get this bright idea is we're going to get this bright idea that man, I don't like reference that man, I don't like reference that man, I don't like reference comparisons for these person objects. comparisons for these person objects. comparisons for these person objects. What if we just compared the values What if we just compared the values What if we just compared the values inside of them? Kind of like records. inside of them? Kind of like records. inside of them? Kind of like records. And we're going to keep coming back to And we're going to keep coming back to And we're going to keep coming back to records over and over because this is records over and over because this is records over and over because this is some of what Microsoft went through and some of what Microsoft went through and some of what Microsoft went through and they created records and it will explain they created records and it will explain they created records and it will explain why records are read only. But we're why records are read only. But we're why records are read only. But we're going to get there in a little bit. So going to get there in a little bit. So going to get there in a little bit. So kind of come back to that. Put a pin kind of come back to that. Put a pin kind of come back to that. Put a pin there. So what if we say you know what there. So what if we say you know what there. So what if we say you know what we want to do comparison. So let's come we want to do comparison. So let's come we want to do comparison. So let's come down to our person class and override down to our person class and override down to our person class and override the equals method the equals method the equals method public override public override public override equals which is a boolean type. And equals which is a boolean type. And equals which is a boolean type. And instead of returning base equals you can instead of returning base equals you can instead of returning base equals you can get rid of that. We can say if the get rid of that. We can say if the get rid of that. We can say if the object being passed in is not person object being passed in is not person object being passed in is not person model model model uh let's just call it uh other.
-
uh let's just call it uh other. uh let's just call it uh other. So if it's not if the object is not a So if it's not if the object is not a So if it's not if the object is not a person model well then they're not equal person model well then they're not equal person model well then they're not equal because this is a person model class. because this is a person model class. because this is a person model class. Therefore if it's we're passing in a Therefore if it's we're passing in a Therefore if it's we're passing in a string or something else it can't equal. string or something else it can't equal. string or something else it can't equal. So we return false. So we return false. So we return false. But notice that what that's going to do But notice that what that's going to do But notice that what that's going to do here is it's going to if it is it's here is it's going to if it is it's here is it's going to if it is it's going to assign other the um the value going to assign other the um the value going to assign other the um the value of like it's going to cast that to a of like it's going to cast that to a of like it's going to cast that to a person model type. So therefore we can person model type. So therefore we can person model type. So therefore we can compare that and let's do a a first name compare that and let's do a a first name compare that and let's do a a first name comparison. This is horrible but we're comparison. This is horrible but we're comparison. This is horrible but we're going to do it. Return first name um going to do it. Return first name um going to do it. Return first name um equals other first name. We're going to equals other first name. We're going to equals other first name. We're going to do the the operator. do the the operator. do the the operator. So, we're going to compare first name So, we're going to compare first name So, we're going to compare first name and other first name. So, are these two and other first name. So, are these two and other first name. So, are these two strings the same? Now, this is nullable strings the same? Now, this is nullable strings the same? Now, this is nullable string. That's going to be kind of string. That's going to be kind of string. That's going to be kind of tricky, but remember double equals tricky, but remember double equals tricky, but remember double equals handles null just fine. So, we're we're handles null just fine. So, we're we're handles null just fine. So, we're we're good there. Um, so it's going to compare good there. Um, so it's going to compare good there. Um, so it's going to compare the object coming in. Does that have the the object coming in. Does that have the the object coming in. Does that have the same first name as my first name? And if same first name as my first name? And if same first name as my first name? And if so, these two objects are equal. Now, so, these two objects are equal. Now, so, these two objects are equal. Now, we're ignoring the last name.
-
we're ignoring the last name. we're ignoring the last name. Just let's go the demo, right? So, this Just let's go the demo, right? So, this Just let's go the demo, right? So, this is the first thing we're going to do. is the first thing we're going to do. is the first thing we're going to do. But you may have heard and it's correct But you may have heard and it's correct But you may have heard and it's correct that if you ever override the equals, that if you ever override the equals, that if you ever override the equals, you should also override the hash code. you should also override the hash code. you should also override the hash code. We're going to do that. I'm going to We're going to do that. I'm going to We're going to do that. I'm going to explain why. So, public explain why. So, public explain why. So, public override override override int get hash code int get hash code int get hash code and we're going to say return and we're going to say return and we're going to say return firstname.get firstname.get firstname.get hash code. hash code. hash code. Okay. So, what's a hash code? Well, a Okay. So, what's a hash code? Well, a Okay. So, what's a hash code? Well, a hash code is an integer. It's a 32bit hash code is an integer. It's a 32bit hash code is an integer. It's a 32bit integer. And what it does is it takes integer. And what it does is it takes integer. And what it does is it takes your object and it says, "Hey, let's your object and it says, "Hey, let's your object and it says, "Hey, let's assign an integer to this based upon the assign an integer to this based upon the assign an integer to this based upon the hash of your object." Um, and and yes, I hash of your object." Um, and and yes, I hash of your object." Um, and and yes, I know that's confusing, but what it's know that's confusing, but what it's know that's confusing, but what it's doing is just giving me a number and doing is just giving me a number and doing is just giving me a number and it's saying this is the number for your it's saying this is the number for your it's saying this is the number for your your your particular instance. So if two your your particular instance. So if two your your particular instance. So if two person models are equal, they should person models are equal, they should person models are equal, they should have a an equal hash code.
-
have a an equal hash code. have a an equal hash code. But that doesn't mean that if you see But that doesn't mean that if you see But that doesn't mean that if you see two hash codes that are equal, it's the two hash codes that are equal, it's the two hash codes that are equal, it's the equal object. And that's called a hash equal object. And that's called a hash equal object. And that's called a hash code collision. Two objects can have the code collision. Two objects can have the code collision. Two objects can have the same number because it's just a 32bit same number because it's just a 32bit same number because it's just a 32bit integer. There can be duplicates, but integer. There can be duplicates, but integer. There can be duplicates, but that's okay. So hash codes make things that's okay. So hash codes make things that's okay. So hash codes make things faster when it comes to lookups. We're faster when it comes to lookups. We're faster when it comes to lookups. We're going to see why. So we're overriding going to see why. So we're overriding going to see why. So we're overriding this to say get the hash code of first this to say get the hash code of first this to say get the hash code of first name since that's what we're comparing name since that's what we're comparing name since that's what we're comparing on. Okay, back up here to our example. on. Okay, back up here to our example. on. Okay, back up here to our example. I intentionally use a dictionary. So a I intentionally use a dictionary. So a I intentionally use a dictionary. So a dictionary uses that hash code for its dictionary uses that hash code for its dictionary uses that hash code for its index. So for the the person model, index. So for the the person model, index. So for the the person model, that's the index. um it's going to use that's the index. um it's going to use that's the index. um it's going to use the hash code. So what happens is when the hash code. So what happens is when the hash code. So what happens is when you create when you add this right here, you create when you add this right here, you create when you add this right here, what it's going to do is it's going to what it's going to do is it's going to what it's going to do is it's going to get the hash code for P1 and it's going get the hash code for P1 and it's going get the hash code for P1 and it's going to say, okay, that hash code goes into a to say, okay, that hash code goes into a to say, okay, that hash code goes into a bucket. So the way it works and let's um bucket. So the way it works and let's um bucket. So the way it works and let's um let's do this. Let's um sorry, let's let's do this. Let's um sorry, let's let's do this. Let's um sorry, let's draw on the screen here. Let's right draw on the screen here. Let's right draw on the screen here. Let's right here. So we have our hash code. Let's here. So we have our hash code. Let's here. So we have our hash code. Let's just say it's 12.
-
just say it's 12. just say it's 12. Well, our our list is going to have Well, our our list is going to have Well, our our list is going to have these buckets and it's going to say these buckets and it's going to say these buckets and it's going to say which bucket does 12 go into? And it's which bucket does 12 go into? And it's which bucket does 12 go into? And it's going to figure out and say, "Oh, that going to figure out and say, "Oh, that going to figure out and say, "Oh, that 12 probably goes into bucket three." And 12 probably goes into bucket three." And 12 probably goes into bucket three." And it's there's a calculation here that it's there's a calculation here that it's there's a calculation here that might be a that's a whole separate might be a that's a whole separate might be a that's a whole separate video. If you're interested in that, we video. If you're interested in that, we video. If you're interested in that, we could potentially do a a video about could potentially do a a video about could potentially do a a video about that. Leave it in the comments or go to that. Leave it in the comments or go to that. Leave it in the comments or go to the suggestion site, leave a suggestion the suggestion site, leave a suggestion the suggestion site, leave a suggestion there. But it's going to put this entry there. But it's going to put this entry there. But it's going to put this entry in this bucket. Okay. So remember these in this bucket. Okay. So remember these in this bucket. Okay. So remember these buckets and they don't have to be buckets and they don't have to be buckets and they don't have to be sequential thing. It's based upon this sequential thing. It's based upon this sequential thing. It's based upon this hash code and it says okay based on that hash code and it says okay based on that hash code and it says okay based on that hash code that hash code goes into this hash code that hash code goes into this hash code that hash code goes into this bucket. Think of it like oh this is you bucket. Think of it like oh this is you bucket. Think of it like oh this is you know 1 to 1 to 5 this is 6 to 11 this is know 1 to 1 to 5 this is 6 to 11 this is know 1 to 1 to 5 this is 6 to 11 this is 12 to 15 something like that. So these 12 to 15 something like that. So these 12 to 15 something like that. So these are known quantities and there's a are known quantities and there's a are known quantities and there's a there's math behind it but it says okay there's math behind it but it says okay there's math behind it but it says okay since it says 12 it goes in the 12 to 15 since it says 12 it goes in the 12 to 15 since it says 12 it goes in the 12 to 15 bucket.
-
bucket. bucket. Okay, so let's come back here and the Okay, so let's come back here and the Okay, so let's come back here and the next one. Maybe that goes into the first next one. Maybe that goes into the first next one. Maybe that goes into the first bucket and maybe this one goes into the bucket and maybe this one goes into the bucket and maybe this one goes into the third bucket as well and maybe this one third bucket as well and maybe this one third bucket as well and maybe this one goes into the fourth bucket. The way the goes into the fourth bucket. The way the goes into the fourth bucket. The way the dictionary works when you come down here dictionary works when you come down here dictionary works when you come down here and say I want something in P4 is it and say I want something in P4 is it and say I want something in P4 is it takes and by the way it stores these takes and by the way it stores these takes and by the way it stores these hash codes so it doesn't have to hash codes so it doesn't have to hash codes so it doesn't have to recalculate. It stores them once as part recalculate. It stores them once as part recalculate. It stores them once as part of storing it in the dictionary. So then of storing it in the dictionary. So then of storing it in the dictionary. So then when we say I want the P4 item, what when we say I want the P4 item, what when we say I want the P4 item, what it's going to do is get the hash code it's going to do is get the hash code it's going to do is get the hash code for this key and it's going to say, for this key and it's going to say, for this key and it's going to say, okay, what bucket would that go in? And okay, what bucket would that go in? And okay, what bucket would that go in? And it finds, oh, that would go into bucket it finds, oh, that would go into bucket it finds, oh, that would go into bucket number, let's just say four or bucket number, let's just say four or bucket number, let's just say four or bucket number two. Bucket number two. So number two. Bucket number two. So number two. Bucket number two. So therefore, it's going to open up bucket therefore, it's going to open up bucket therefore, it's going to open up bucket number two in its entire list, only look number two in its entire list, only look number two in its entire list, only look in that bucket, [clears throat] and then in that bucket, [clears throat] and then in that bucket, [clears throat] and then start looking through the hash codes and start looking through the hash codes and start looking through the hash codes and comparing them. comparing them. comparing them. and it says, "Does this hash code is and it says, "Does this hash code is and it says, "Does this hash code is this hash code the same as the P4's hash this hash code the same as the P4's hash this hash code the same as the P4's hash code?" Nope. Then skip. And goes through code?" Nope. Then skip. And goes through code?" Nope. Then skip. And goes through and compares those hash codes until it and compares those hash codes until it and compares those hash codes until it finds one that matches. But remember, finds one that matches. But remember, finds one that matches. But remember, you can have hash code collision. And so you can have hash code collision. And so you can have hash code collision. And so the hash code collision says the hash the hash code collision says the hash the hash code collision says the hash codes might be the same, but the values codes might be the same, but the values codes might be the same, but the values might be different. And so if it finds might be different. And so if it finds might be different. And so if it finds there's a value that match or a hash there's a value that match or a hash there's a value that match or a hash code that matches in it in its bucket, code that matches in it in its bucket, code that matches in it in its bucket, it then says, "Okay, now let's run the it then says, "Okay, now let's run the it then says, "Okay, now let's run the equals method and see if these two are
-
equals method and see if these two are equals method and see if these two are equal. And if they are, cool, we're equal. And if they are, cool, we're equal. And if they are, cool, we're done." If we're not, keep looking. Okay, done." If we're not, keep looking. Okay, done." If we're not, keep looking. Okay, so that's how our dictionary and other so that's how our dictionary and other so that's how our dictionary and other types, hashets, and uh frozen lists work types, hashets, and uh frozen lists work types, hashets, and uh frozen lists work as well. Um so that's how they work is as well. Um so that's how they work is as well. Um so that's how they work is they use not every collection does not they use not every collection does not they use not every collection does not like list doesn't do that but certain like list doesn't do that but certain like list doesn't do that but certain collections that use the hash set that's collections that use the hash set that's collections that use the hash set that's how they they work that's important to how they they work that's important to how they they work that's important to understand because and not not all the understand because and not not all the understand because and not not all the specifics but in general that they use specifics but in general that they use specifics but in general that they use the hash set and then they use the the hash set and then they use the the hash set and then they use the equals method. By the way, doing an equals method. By the way, doing an equals method. By the way, doing an equals on every single value would be equals on every single value would be equals on every single value would be expensive. Running this method over and expensive. Running this method over and expensive. Running this method over and over and over again. Let's say you have over and over again. Let's say you have over and over again. Let's say you have 10,000 records in a dictionary. Super 10,000 records in a dictionary. Super 10,000 records in a dictionary. Super expensive. Comparing hashets, super expensive. Comparing hashets, super expensive. Comparing hashets, super fast. That's why they do it. Okay. But fast. That's why they do it. Okay. But fast. That's why they do it. Okay. But if we have this override now for equals if we have this override now for equals if we have this override now for equals comparing the first name to the first comparing the first name to the first comparing the first name to the first name, we say well then if that's the name, we say well then if that's the name, we say well then if that's the case then we need to also update the get case then we need to also update the get case then we need to also update the get hash code to match. That way we don't hash code to match. That way we don't hash code to match. That way we don't have this case where the hash codes are have this case where the hash codes are have this case where the hash codes are are correct but the equals will never be are correct but the equals will never be are correct but the equals will never be in the right spot. We want to make sure in the right spot. We want to make sure in the right spot. We want to make sure these two are in alignment because they these two are in alignment because they these two are in alignment because they essentially are pointing to the same essentially are pointing to the same essentially are pointing to the same thing. So, we've now aligned them. But thing. So, we've now aligned them. But thing. So, we've now aligned them. But what is that going to do? Remember,
-
what is that going to do? Remember, what is that going to do? Remember, we're just checking on first name. we're just checking on first name. we're just checking on first name. Horrible way of doing things for equals, Horrible way of doing things for equals, Horrible way of doing things for equals, but let's just pretend that that's the but let's just pretend that that's the but let's just pretend that that's the reason we're going to do that. Well, we reason we're going to do that. Well, we reason we're going to do that. Well, we have two Tims up here. So the first have two Tims up here. So the first have two Tims up here. So the first thing that's going to happen if we run thing that's going to happen if we run thing that's going to happen if we run this this this is it'll crash and it says an item of is it'll crash and it says an item of is it'll crash and it says an item of the same key has already been added. the same key has already been added. the same key has already been added. So we can't even add P4. Why? Because So we can't even add P4. Why? Because So we can't even add P4. Why? Because we're doing a comparison and hashet code we're doing a comparison and hashet code we're doing a comparison and hashet code on Tim. And so therefore the hashet code on Tim. And so therefore the hashet code on Tim. And so therefore the hashet code says hey these two are the same. And the says hey these two are the same. And the says hey these two are the same. And the value comparison we checked that too value comparison we checked that too value comparison we checked that too says the value is the same. Therefore we says the value is the same. Therefore we says the value is the same. Therefore we can't add this record even though can't add this record even though can't add this record even though they're technically different which is they're technically different which is they're technically different which is why we wouldn't ever wouldn't want to do why we wouldn't ever wouldn't want to do why we wouldn't ever wouldn't want to do this. But let's just say that we could this. But let's just say that we could this. But let's just say that we could go oh well that was just a bug. So I'm go oh well that was just a bug. So I'm go oh well that was just a bug. So I'm going to get rid of this. I'm going to going to get rid of this. I'm going to going to get rid of this. I'm going to run it again and it runs. Are P1 and P4 run it again and it runs. Are P1 and P4 run it again and it runs. Are P1 and P4 equal? True. Because they both have Tim equal? True. Because they both have Tim equal? True. Because they both have Tim for the first name. That's what we for the first name. That's what we for the first name. That's what we expect. Is P4 in the dictionary? Yes, expect. Is P4 in the dictionary? Yes, expect. Is P4 in the dictionary? Yes, it's the dictionary is value is five.
-
it's the dictionary is value is five. it's the dictionary is value is five. Wait a minute. What? We didn't add P4 to Wait a minute. What? We didn't add P4 to Wait a minute. What? We didn't add P4 to the dictionary took it out. Well, yes, the dictionary took it out. Well, yes, the dictionary took it out. Well, yes, but because the comparison in the hashet but because the comparison in the hashet but because the comparison in the hashet code being with the R, it said that code being with the R, it said that code being with the R, it said that record P1 matches. Therefore, P1 matches record P1 matches. Therefore, P1 matches record P1 matches. Therefore, P1 matches P4. Therefore, when you look up P4 in P4. Therefore, when you look up P4 in P4. Therefore, when you look up P4 in the dictionary, you're going to find P1. the dictionary, you're going to find P1. the dictionary, you're going to find P1. That's a problem. That's a problem. That's a problem. Okay, so we want to make sure we don't Okay, so we want to make sure we don't Okay, so we want to make sure we don't do something silly like this. But it can do something silly like this. But it can do something silly like this. But it can get even worse than that because what if get even worse than that because what if get even worse than that because what if down here I were to say, you know what, down here I were to say, you know what, down here I were to say, you know what, P1 uh first name is actually Timothy. P1 uh first name is actually Timothy. P1 uh first name is actually Timothy. That's my government name. So what That's my government name. So what That's my government name. So what happens? Well, it really messes things happens? Well, it really messes things happens? Well, it really messes things up because we've overridden the up because we've overridden the up because we've overridden the comparison. Now it might or might not comparison. Now it might or might not comparison. Now it might or might not show up. It did. Okay, so perfect. show up. It did. Okay, so perfect. show up. It did. Okay, so perfect. So, first of all, let's go back to our So, first of all, let's go back to our So, first of all, let's go back to our our console here. P1 and P4 not equal or our console here. P1 and P4 not equal or our console here. P1 and P4 not equal or false. And then we're saying is P4 in a false. And then we're saying is P4 in a false. And then we're saying is P4 in a dictionary. Um, it says the key was not dictionary. Um, it says the key was not dictionary. Um, it says the key was not found. Well, why? Because we changed found. Well, why? Because we changed found. Well, why? Because we changed P1's first name and [snorts] that was a P1's first name and [snorts] that was a P1's first name and [snorts] that was a problem.
-
problem. problem. Okay, but the way that this worked is Okay, but the way that this worked is Okay, but the way that this worked is that it probably did find P1 as a hashet that it probably did find P1 as a hashet that it probably did find P1 as a hashet match match match because of the fact that it was Tim when because of the fact that it was Tim when because of the fact that it was Tim when we inserted it into the dictionary. And we inserted it into the dictionary. And we inserted it into the dictionary. And what it does when it does gets that what it does when it does gets that what it does when it does gets that hashet code um is it stores it at that hashet code um is it stores it at that hashet code um is it stores it at that time. it does not recalculate it every time. it does not recalculate it every time. it does not recalculate it every time we do a new search because that time we do a new search because that time we do a new search because that would be inefficient. So because it got would be inefficient. So because it got would be inefficient. So because it got the hash code and then we changed how the hash code and then we changed how the hash code and then we changed how the hash code is is created. the hash code is is created. the hash code is is created. Remember down here the hash code is Remember down here the hash code is Remember down here the hash code is created off of the first name. Well now created off of the first name. Well now created off of the first name. Well now the hash code is made different for P1 the hash code is made different for P1 the hash code is made different for P1 than it used to be. So that's why it can than it used to be. So that's why it can than it used to be. So that's why it can cause a real problem when you override cause a real problem when you override cause a real problem when you override the equality method the equality method the equality method because if it's already in a list that because if it's already in a list that because if it's already in a list that uses the hash set then you've got a uses the hash set then you've got a uses the hash set then you've got a problem with the lookup where it can't problem with the lookup where it can't problem with the lookup where it can't find it anymore. So that can be find it anymore. So that can be find it anymore. So that can be problematic. Okay. So what are some problematic. Okay. So what are some problematic. Okay. So what are some options here for making this better?
-
options here for making this better? options here for making this better? Well, first of all what we can do is we Well, first of all what we can do is we Well, first of all what we can do is we can come down here and change this to can come down here and change this to can come down here and change this to use first name and last name. use first name and last name. use first name and last name. So, and last name equals other.ast name. So, and last name equals other.ast name. So, and last name equals other.ast name. Now, this can get really complicated if Now, this can get really complicated if Now, this can get really complicated if you have multiple things, but just note you have multiple things, but just note you have multiple things, but just note that um you kind have to do that. Uh and that um you kind have to do that. Uh and that um you kind have to do that. Uh and then down here, we can return the uh then down here, we can return the uh then down here, we can return the uh hash uh hashcode. hash uh hashcode. hash uh hashcode. combine and then say first name last combine and then say first name last combine and then say first name last name and this creates combined value name and this creates combined value name and this creates combined value hash code uh for we have to do our own hash code uh for we have to do our own hash code uh for we have to do our own calculation for hash code um which by calculation for hash code um which by calculation for hash code um which by the way we could um that would be a a the way we could um that would be a a the way we could um that would be a a messy thing don't do that um but you can messy thing don't do that um but you can messy thing don't do that um but you can just use hashcode combine to combine any just use hashcode combine to combine any just use hashcode combine to combine any number of parameters that you're passing number of parameters that you're passing number of parameters that you're passing in um as well. So now we have things a in um as well. So now we have things a in um as well. So now we have things a little better because we can get rid of little better because we can get rid of little better because we can get rid of let's stop. Um let's let's not do this.
-
let's stop. Um let's let's not do this. let's stop. Um let's let's not do this. Um but we can put P4 in the dictionary Um but we can put P4 in the dictionary Um but we can put P4 in the dictionary now. Um because P1 P4 are not equal. now. Um because P1 P4 are not equal. now. Um because P1 P4 are not equal. Remember P1 is Tim Corey and P4 is Tim Remember P1 is Tim Corey and P4 is Tim Remember P1 is Tim Corey and P4 is Tim Smith. And P4 is in the dictionary and Smith. And P4 is in the dictionary and Smith. And P4 is in the dictionary and the value is one which is correct. the value is one which is correct. the value is one which is correct. So that can work, but we still have the So that can work, but we still have the So that can work, but we still have the problem of changing the first name can problem of changing the first name can problem of changing the first name can cause problems because the fact that cause problems because the fact that cause problems because the fact that we're changing how the equality works. we're changing how the equality works. we're changing how the equality works. We're changing how the um hash set gets We're changing how the um hash set gets We're changing how the um hash set gets calculated after it's already in a a calculated after it's already in a a calculated after it's already in a a list or a dictionary that has pre-done list or a dictionary that has pre-done list or a dictionary that has pre-done the um the hash code. So the um the hash code. So the um the hash code. So that can be problematic. So what do you that can be problematic. So what do you that can be problematic. So what do you do in that case? Well, what you do is do in that case? Well, what you do is do in that case? Well, what you do is you make it read only because that way you make it read only because that way you make it read only because that way you can't change the first name after you can't change the first name after you can't change the first name after the fact, which if you've ever used a the fact, which if you've ever used a the fact, which if you've ever used a record, that's how records work. And record, that's how records work. And record, that's how records work. And people go, "Oh, I wish they weren't read people go, "Oh, I wish they weren't read people go, "Oh, I wish they weren't read only." That's why because they've only." That's why because they've only." That's why because they've overridden the equality in the the um overridden the equality in the the um overridden the equality in the the um down here the the hash code. So if you down here the the hash code. So if you down here the the hash code. So if you override that to do a comparison of override that to do a comparison of override that to do a comparison of value comparison of all of the the value comparison of all of the the value comparison of all of the the properties that are inside of it, well properties that are inside of it, well properties that are inside of it, well then if you change a property but it's then if you change a property but it's then if you change a property but it's already in a dictionary, that's a already in a dictionary, that's a already in a dictionary, that's a problem as a as a key by the way um or problem as a as a key by the way um or problem as a as a key by the way um or in a hash sent as the the value um or
-
in a hash sent as the the value um or in a hash sent as the the value um or other types. So other types. So other types. So just know that that's why we make things just know that that's why we make things just know that that's why we make things read only which is then you go well this read only which is then you go well this read only which is then you go well this doesn't make sense then to do this doesn't make sense then to do this doesn't make sense then to do this you're correct in most cases it doesn't you're correct in most cases it doesn't you're correct in most cases it doesn't and if it does maybe choose a record and if it does maybe choose a record and if it does maybe choose a record type um but maybe there are some things type um but maybe there are some things type um but maybe there are some things that you don't change for example if you that you don't change for example if you that you don't change for example if you had an a employee ID that probably had an a employee ID that probably had an a employee ID that probably doesn't change so therefore you could doesn't change so therefore you could doesn't change so therefore you could make that innit only so you could get make that innit only so you could get make that innit only so you could get have a get and a nit and then make that have a get and a nit and then make that have a get and a nit and then make that what you do equal comparison on because what you do equal comparison on because what you do equal comparison on because if the employee ID matches the employee if the employee ID matches the employee if the employee ID matches the employee ID, it's the same person. ID, it's the same person. ID, it's the same person. So then that would be a valid override So then that would be a valid override So then that would be a valid override for equals and get hash code. Now, so for equals and get hash code. Now, so for equals and get hash code. Now, so far what I've done is just um done the far what I've done is just um done the far what I've done is just um done the changed how equals works. But let's also changed how equals works. But let's also changed how equals works. But let's also change the operator. So how do you change the operator. So how do you change the operator. So how do you change equals and not equals? And by the change equals and not equals? And by the change equals and not equals? And by the way, I would encourage you if you're way, I would encourage you if you're way, I would encourage you if you're going to change equals and get hash going to change equals and get hash going to change equals and get hash code, you should probably look at at code, you should probably look at at code, you should probably look at at changing the operator as well. Now, changing the operator as well. Now, changing the operator as well. Now, people will tell you there are times people will tell you there are times people will tell you there are times when you don't have to do that. Where when you don't have to do that. Where when you don't have to do that. Where you could say, you know what, I'm just you could say, you know what, I'm just you could say, you know what, I'm just going to change equals but not the going to change equals but not the going to change equals but not the operator. I would say that those cases operator. I would say that those cases operator. I would say that those cases are so rare as to not worry about for are so rare as to not worry about for are so rare as to not worry about for your defaults. Okay, your default is your defaults. Okay, your default is your defaults. Okay, your default is change them all. Otherwise you have this change them all. Otherwise you have this change them all. Otherwise you have this weird thing where double equals says no
-
weird thing where double equals says no weird thing where double equals says no because it's a reference check whereas because it's a reference check whereas because it's a reference check whereas equals says yes because it's a equals says yes because it's a equals says yes because it's a overridden essentially value check. Um I overridden essentially value check. Um I overridden essentially value check. Um I don't love that. So I don't like you don't love that. So I don't like you don't love that. So I don't like you know finding out that there's a um a know finding out that there's a um a know finding out that there's a um a surprise hidden in there. So public surprise hidden in there. So public surprise hidden in there. So public static bool operator static bool operator static bool operator double equals double equals double equals and we're going to say person model uh and we're going to say person model uh and we're going to say person model uh we'll say nullable left we'll say nullable left we'll say nullable left and person model uh that's nullable and person model uh that's nullable and person model uh that's nullable right. right. right. Okay. So we're going to change how the Okay. So we're going to change how the Okay. So we're going to change how the operator works. if reference equals operator works. if reference equals operator works. if reference equals remember reference equals that's going remember reference equals that's going remember reference equals that's going to check the reference no matter what. to check the reference no matter what. to check the reference no matter what. So left and right So left and right So left and right um then what we're going to do is if um then what we're going to do is if um then what we're going to do is if it's true it's true it's true return return return true. I don't know why I have this extra true. I don't know why I have this extra true. I don't know why I have this extra curly brace here. That's annoying.
-
curly brace here. That's annoying. curly brace here. That's annoying. Wow, that really really messed up me. Wow, that really really messed up me. Wow, that really really messed up me. There we go. Um ah down there that's why There we go. Um ah down there that's why There we go. Um ah down there that's why okay after only formatting is done if okay after only formatting is done if okay after only formatting is done if the reference equal for left and right the reference equal for left and right the reference equal for left and right are the same then return true. So that's are the same then return true. So that's are the same then return true. So that's just going to say hey if if the memory just going to say hey if if the memory just going to say hey if if the memory registers are the same then it doesn't registers are the same then it doesn't registers are the same then it doesn't matter if you are if you've overridden matter if you are if you've overridden matter if you are if you've overridden equals or not they're the same thing equals or not they're the same thing equals or not they're the same thing because the same memory reference because the same memory reference because the same memory reference therefore everything will match the therefore everything will match the therefore everything will match the same. Therefore, we can just shortcut same. Therefore, we can just shortcut same. Therefore, we can just shortcut this and say at the reference equals is this and say at the reference equals is this and say at the reference equals is the same then return true. Um then we the same then return true. Um then we the same then return true. Um then we can say if can say if can say if left is null or right is null left is null or right is null left is null or right is null return false because if one of them is return false because if one of them is return false because if one of them is null then they're not equal. And if both null then they're not equal. And if both null then they're not equal. And if both of them are null then their reference of them are null then their reference of them are null then their reference would be equal. Therefore, only one of would be equal. Therefore, only one of would be equal. Therefore, only one of them is is null. them is is null. them is is null. Okay. But if neither is null and the Okay. But if neither is null and the Okay. But if neither is null and the reference equals not correct, then what reference equals not correct, then what reference equals not correct, then what we're going to do is return we're going to do is return we're going to do is return left.
-
left. left. Right? So, we're going to call our Right? So, we're going to call our Right? So, we're going to call our overridden equals to do our comparison. overridden equals to do our comparison. overridden equals to do our comparison. That way, not duplicating uh code or or That way, not duplicating uh code or or That way, not duplicating uh code or or trying to have it in two places at once. trying to have it in two places at once. trying to have it in two places at once. We're keeping it dry. All right. So now We're keeping it dry. All right. So now We're keeping it dry. All right. So now that will handle our equals. But notice that will handle our equals. But notice that will handle our equals. But notice the red squiggies. It says the operator the red squiggies. It says the operator the red squiggies. It says the operator double equal requires a matching double equal requires a matching double equal requires a matching operator of not equal to also be operator of not equal to also be operator of not equal to also be defined. Okay. So if you have equal defined. Okay. So if you have equal defined. Okay. So if you have equal or double equals then you have to and or double equals then you have to and or double equals then you have to and you're you're changing that then you you're you're changing that then you you're you're changing that then you also have to change how not equals work. also have to change how not equals work. also have to change how not equals work. So public static bool operator So public static bool operator So public static bool operator not equal not equal not equal and we're going to pass in the same uh and we're going to pass in the same uh and we're going to pass in the same uh person left and person right. And we'll come down here And we'll come down here and we're going to say and we're going to say and we're going to say return return return not not not left equals right which what's that doing? It's using our which what's that doing? It's using our double equals which is up here. We've double equals which is up here. We've double equals which is up here. We've done all this logic. Why not just use done all this logic. Why not just use done all this logic. Why not just use that logic over again and just flip the that logic over again and just flip the that logic over again and just flip the bit. Okay. So what it's going to do is bit. Okay. So what it's going to do is bit. Okay. So what it's going to do is return the opposite of equals. So return the opposite of equals. So return the opposite of equals. So essentially anytime you call not equals essentially anytime you call not equals essentially anytime you call not equals in this case for us we are saying in this case for us we are saying in this case for us we are saying actually you're calling equals behind actually you're calling equals behind actually you're calling equals behind the scenes and just flipping that. So
-
the scenes and just flipping that. So the scenes and just flipping that. So what that's done now is it's changed how what that's done now is it's changed how what that's done now is it's changed how equality works. So let's come up here equality works. So let's come up here equality works. So let's come up here and we've got our equals here. Let's and we've got our equals here. Let's and we've got our equals here. Let's just run this again. Okay. Uh false. just run this again. Okay. Uh false. just run this again. Okay. Uh false. Let's copy this. Let's control D to Let's copy this. Let's control D to Let's copy this. Let's control D to duplicate it. Um we're going to say duplicate it. Um we're going to say duplicate it. Um we're going to say double equals and say double equals and say double equals and say P1 double equals P4. P1 double equals P4. P1 double equals P4. Okay. And we run it again. And of Okay. And we run it again. And of Okay. And we run it again. And of course, we get false again. Cool. That's course, we get false again. Cool. That's course, we get false again. Cool. That's actually what we want. And in fact, if actually what we want. And in fact, if actually what we want. And in fact, if we Well, let's not worry about comparing we Well, let's not worry about comparing we Well, let's not worry about comparing two different objects. We're going to two different objects. We're going to two different objects. We're going to change um Smith to be cord. Okay. And we have to take them out of Okay. And we have to take them out of the dictionary that way because now they the dictionary that way because now they the dictionary that way because now they are the same. Um but now P1 P4 equals are the same. Um but now P1 P4 equals are the same. Um but now P1 P4 equals true. And P1 P4 equal is true. So it's true. And P1 P4 equal is true. So it's true. And P1 P4 equal is true. So it's doing the comparison for us. And by the doing the comparison for us. And by the doing the comparison for us. And by the way, it does find P4 in the dictionary way, it does find P4 in the dictionary way, it does find P4 in the dictionary again because it's actually P1 it's again because it's actually P1 it's again because it's actually P1 it's finding okay because they're equal.
-
finding okay because they're equal. finding okay because they're equal. Therefore, you know, finding P1, but it Therefore, you know, finding P1, but it Therefore, you know, finding P1, but it equals P or P4, but it equals P1. equals P or P4, but it equals P1. equals P or P4, but it equals P1. Therefore, it finds P1 in the Therefore, it finds P1 in the Therefore, it finds P1 in the dictionary. dictionary. dictionary. So that's how you would change how the So that's how you would change how the So that's how you would change how the double equals works. Um, and again, my double equals works. Um, and again, my double equals works. Um, and again, my personal preference is that if you're personal preference is that if you're personal preference is that if you're going to change equals, change that git going to change equals, change that git going to change equals, change that git hash code for sure and then also change hash code for sure and then also change hash code for sure and then also change equals and not equals because otherwise equals and not equals because otherwise equals and not equals because otherwise you lead to confusion with people with you lead to confusion with people with you lead to confusion with people with your developers. And the the one your developers. And the the one your developers. And the the one argument against changing the double argument against changing the double argument against changing the double equals is well, but if the double equals equals is well, but if the double equals equals is well, but if the double equals is a reference comparison and now it's a is a reference comparison and now it's a is a reference comparison and now it's a value comparison. Well, yes, that's value comparison. Well, yes, that's value comparison. Well, yes, that's true. But you always have the reference true. But you always have the reference true. But you always have the reference equals that's always available. So equals that's always available. So equals that's always available. So therefore, you can still do reference therefore, you can still do reference therefore, you can still do reference comparisons without a problem, but now comparisons without a problem, but now comparisons without a problem, but now your double equals matches your equals your double equals matches your equals your double equals matches your equals and they're both overridden. But again, and they're both overridden. But again, and they're both overridden. But again, if you're doing it based upon properties if you're doing it based upon properties if you're doing it based upon properties that are changeable, you're going to that are changeable, you're going to that are changeable, you're going to have problems if they're in a place that have problems if they're in a place that have problems if they're in a place that uses the hash code. Therefore, I would uses the hash code. Therefore, I would uses the hash code. Therefore, I would change these from sets to init.
-
That way, you cannot change the first That way, you cannot change the first and last name, which it depends on after and last name, which it depends on after and last name, which it depends on after [clears throat] the fact. So, now if we [clears throat] the fact. So, now if we [clears throat] the fact. So, now if we run this, nothing's going to change. run this, nothing's going to change. run this, nothing's going to change. Still works. But if I were to come down Still works. But if I were to come down Still works. But if I were to come down here and say P1.irstame equals Timothy, here and say P1.irstame equals Timothy, here and say P1.irstame equals Timothy, can't do it because it's innit only. So can't do it because it's innit only. So can't do it because it's innit only. So I can only change it in the constructor I can only change it in the constructor I can only change it in the constructor or when you assign it um through or when you assign it um through or when you assign it um through instantiation but I can't change it now instantiation but I can't change it now instantiation but I can't change it now because it's too late. It's read only at because it's too late. It's read only at because it's too late. It's read only at this point. Therefore I can't mess up my this point. Therefore I can't mess up my this point. Therefore I can't mess up my dictionary. Okay. So that's how equality dictionary. Okay. So that's how equality dictionary. Okay. So that's how equality works. That's how you can ch That's how works. That's how you can ch That's how works. That's how you can ch That's how you can change equality and you can make you can change equality and you can make you can change equality and you can make your classes act more like value types your classes act more like value types your classes act more like value types when it comes to equals uh the method as when it comes to equals uh the method as when it comes to equals uh the method as well as the double equals operator. Um well as the double equals operator. Um well as the double equals operator. Um but also kind of the pitfalls that you but also kind of the pitfalls that you but also kind of the pitfalls that you run into if you ever use something where run into if you ever use something where run into if you ever use something where the hash code is being used. So be the hash code is being used. So be the hash code is being used. So be careful there. Um again if you want more careful there. Um again if you want more careful there. Um again if you want more information on how hash codes are information on how hash codes are information on how hash codes are actually work worked with lists and not actually work worked with lists and not actually work worked with lists and not with lists but with um dictionaries and with lists but with um dictionaries and with lists but with um dictionaries and other types uh let me know but there's other types uh let me know but there's other types uh let me know but there's some complicated stuff going be going on some complicated stuff going be going on some complicated stuff going be going on behind the scenes in order to make this behind the scenes in order to make this behind the scenes in order to make this very very efficient and if you don't very very efficient and if you don't very very efficient and if you don't know why you go that's a stupid decision know why you go that's a stupid decision know why you go that's a stupid decision and once you understand more you're like and once you understand more you're like and once you understand more you're like that was a smart decision. This is why that was a smart decision. This is why that was a smart decision. This is why records are readon because they're records are readon because they're records are readon because they're immutable because of the fact that if we immutable because of the fact that if we immutable because of the fact that if we were to change it, it would break things
-
were to change it, it would break things were to change it, it would break things in our dictionary. There's a case where in our dictionary. There's a case where in our dictionary. There's a case where the hash because the the hash code might the hash because the the hash code might the hash because the the hash code might be, you know, the previous hash code be, you know, the previous hash code be, you know, the previous hash code that you might in the dictionary go that you might in the dictionary go that you might in the dictionary go looking for something in a certain looking for something in a certain looking for something in a certain bucket and it's not there even though bucket and it's not there even though bucket and it's not there even though that actual value is in the dictionary that actual value is in the dictionary that actual value is in the dictionary just in a different bucket now or just just in a different bucket now or just just in a different bucket now or just in a different bucket and it would not in a different bucket and it would not in a different bucket and it would not find it or it might be in the bucket but find it or it might be in the bucket but find it or it might be in the bucket but because the hash codes are going the because the hash codes are going the because the hash codes are going the equality being different. It's not going equality being different. It's not going equality being different. It's not going to find it either. It's just you can to find it either. It's just you can to find it either. It's just you can create some really messy situations if create some really messy situations if create some really messy situations if you don't you don't you don't pair these two especially together. So pair these two especially together. So pair these two especially together. So change equals means change git hash change equals means change git hash change equals means change git hash code. And also if the equality and the code. And also if the equality and the code. And also if the equality and the git hash code if those are based upon git hash code if those are based upon git hash code if those are based upon things that are mutable changeable things that are mutable changeable things that are mutable changeable that's a problem. Therefore make them uh that's a problem. Therefore make them uh that's a problem. Therefore make them uh no longer changeable after the initial no longer changeable after the initial no longer changeable after the initial construction. That way you don't cause construction. That way you don't cause construction. That way you don't cause problems later on for yourself. That's a problems later on for yourself. That's a problems later on for yourself. That's a a bug that can cause some serious issues a bug that can cause some serious issues a bug that can cause some serious issues in your code that you're not sure why in your code that you're not sure why in your code that you're not sure why it's happening, especially since it it's happening, especially since it it's happening, especially since it could cause problems or it could not could cause problems or it could not could cause problems or it could not cause problems, which is just really cause problems, which is just really cause problems, which is just really messy. So, make sure you understand how messy. So, make sure you understand how messy. So, make sure you understand how to change these things, but also how to to change these things, but also how to to change these things, but also how to safely change these things and maybe why safely change these things and maybe why safely change these things and maybe why you don't want to do that and why if you you don't want to do that and why if you you don't want to do that and why if you really want this, you know, this kind of really want this, you know, this kind of really want this, you know, this kind of value comparison, use record type value comparison, use record type value comparison, use record type instead. that takes care of it for you.
-
instead. that takes care of it for you. instead. that takes care of it for you. And yes, they're mutable or immutable, And yes, they're mutable or immutable, And yes, they're mutable or immutable, but they also have a way to create new but they also have a way to create new but they also have a way to create new records based upon the old value and records based upon the old value and records based upon the old value and just changing some things. So, they have just changing some things. So, they have just changing some things. So, they have some shortcuts even there. Okay, thanks some shortcuts even there. Okay, thanks some shortcuts even there. Okay, thanks for watching and as always, I am Tim for watching and as always, I am Tim for watching and as always, I am Tim Corey. [music]
No summary available yet.
View original episode ↗