Transcript from the "Lifetimes Solution" Lesson
>> So once again, we have somewhat of a choice to make here. We definitely are going to need to make some product an average, take either slices or vector references. I'm gonna start by just doing References and now I should be able to call some of numbers. But of course that's not gonna compile because I need to borrow it.
[00:00:24] So I can do it like that and then product ampersand numbers, not double ampersand and finally average of ampersand numbers. Okay, next we want to go look at this first three function which is going to take some, either a slice of ice 64 or a reference to a vector of ice 64.
[00:00:51] And then is gonna return a slice. So let's start by having it work that way. Now notice, by the way that when we call first three we're potentially giving it an own copy of this. So if we want, we don't necessarily need to make any change here. If we want, we can just like leave this alone and just have it pass in the own value, but that is a little bit more restrictive in the sense that we are just returning slices here so we don't necessarily need to do that.
[00:01:19] But as we'll see in a second, if I try to do it this way, it actually makes it a little bit more annoying and complicated to try and express how we're gonna be returning these slices. And in fact, it's gonna cause a problem when I change the return type to try to return a slice.
[00:01:35] So let's just see that problem and actually, then we'll solve it. Okay, so we will return two slices one contain the first three elements in numbers one, the other contain the first three elements, numbers two. So here's the syntax for doing that. So I'm just gonna say let slice one equals that.
[00:01:48] And so that's gonna be numbers one and then this is gonna be numbers two. And this is gonna be slice two. All right, so we have two slices now, so far so good. And now I want to return them. So let's see what happens when I go to return these slices.
[00:02:03] So instead of numbers one or numbers two, I'm now returning slice one and slice two. Okay, well immediately we're gonna have a problem, which is a type mismatch because it's saying, hey, I expected a vac of Ice 64 because that's what it says we're returning. But when I actually got was a slice of ice 64, okay?
[00:02:21] Fair enough, so let's change this to be returning slices. And now we have a new problem, which is it says, hey, missing lifetime specify, this function has returned type contains a borrowed value within the lighted lifetime, but the lifetime cannot be derived from the arguments. So we wanna pause here and just imagine if we hadn't just gone through this section on ownership, borrowing and lifetimes.
[00:02:49] What would you think of this error message? Missing lifetime specifier this functions return type contains a borrowed value within a lighted lifetime, with a lifetime cannot be derived from the arguments, what could that possibly mean? Hopefully now you can see from this error message, a why we spent so much time building up to this and b, why the course gets into this stuff.
[00:03:08] These things can be incredibly frustrating as a beginner if you have no idea what any of this terminology means. So the reason that I spent so much time in this course like building up a mental model of how the memory works, and the purpose of each of these things is, I don't expect you to have a perfect understanding of these things by this point.
[00:03:22] But hopefully, especially if you wanna go back and re-review some of the parts of the workshop earlier. This gives you some sense of what's going on here. So basically, what it's saying is hey, I couldn't figure out what the lifetimes of these things could be, I couldn't successfully allied them.
[00:03:36] So I need you to add a lifetime specifier to do that. So that's what we're gonna have to do. We're gonna have to actually change this to be not just ampersand but something like tick a and possibly tick b. So let's try it with tick a first and see what happens, so it says okay, use of undeclared lifetime tick a.
[00:03:51] All right, fair enough I forgot to do that let's just put that in there. Okay, great now we're doing this. So, I've now said okay, these two slices have the same lifetime. These two slices that I'm returning same lifetime. Great, but I've got an error it says cod return value referencing function parameter numbers two returns a value referencing data owned by the current function.
[00:04:11] So what does that mean? Data owned by the current function. Well, we've declared these as owned arguments, right? I decided I wasn't gonna change this to be a reference type, so this is now an owned vac. If I had an ampersand here, it would be a reference but I didn't, so not there.
[00:04:27] [LAUGH] If I had an ampersand here, it would be an owned vac. But I didn't do that instead, I'm accepting an owned value. And one of the things we know about owned values is if this function owns this vac, it's gonna get deallocated at the end. So here, this is receiving from a use after free, right?
[00:04:44] So I'm trying to return slices to this thing, but also I'm going to be deallocating it by default, this would be a use after free but instead it's a no, no. I Can't return a value referencing this parameter because this references data owned by the current function and owned by really is kind of translated into is going to get de allocated at the end of.
[00:05:03] So that's what the error is telling us. It's saying these owned values are a problem because [LAUGH] They're gonna get de allocated at the end here. So how do we fix that? Well, we don't make them owned, we make them be references. Okay, so let's do that and then go back to first three here and so now in order to pass those in, I need to borrow them.
[00:05:21] Okay, that's why it was complaining that there's a red squiggle there, so we fixed that. So now that type mismatch is fixed, great, but now we come back and we have another error. Says explicit lifetime required in the type of numbers one lifetime tick a required. This is an interesting example where it figured out that it's like okay, I know that there should be a lifetime annotation here.
[00:05:42] I need you to write it out but I also know what it is, which is, [LAUGH] I know that it's tick a. This is kind of a weird case of the example of like lifetime illusion where it's like it was able to figure out what the lifetime should have been, but it still wants you to write it out.
[00:05:55] Again, imagine seeing this, [LAUGH] like for the first time when you're a beginner, if you don't know what lifetimes are, it can be kinda confusing. So all right, we're gonna add tick a in both of these places, and hey, look at that. No more compile errors, let's see what happens when we run it.
[00:06:11] Cool, first of all with a slice one, R 2, 4 and 6, the first VM with slice, two R 1,2 and 3. Great everything worked. Now real quick, I want to point out this is not the only way to solve solve this. There is another way we could do this, which is if we wanted to, we could actually claim that these two have decoupled lifetimes, I could add a second lifetime here and say tick b.
[00:06:30] So let me try something that's not gonna work. And then we'll see how it's gonna not work. So let's say I added a tick b here. And I just said, you know what? Just this one has tick b says, wait a minute. No, that's an error, what's the error?
[00:06:42] It says lifetime mismatch. [LAUGH] So basically it says this parameter and the return type are declared with different lifetimes, but data from numbers two is returned here. So basically I said this argument has the lifetime tick b, but then I referenced it in slice two and try to return that and then when over here I claimed that has the lifetime tick and it's like no, no that's wrong.
[00:07:01] See these are connected this is a slice of numbers two, numbers two has lifetime tick b, therefore slice two also needs to have a lifetime of tick b. And sure enough, if I change this to that, now it's happy again, and everything's cool. So what's the difference between this version with tick a and tick b versus the version I had a second ago were both are tick a?
[00:07:21] Well, basically this version that I have here is sort of strictly more flexible, because this accepts more possibilities than the other way that I have it where everything was today. Another way of saying this is that here I'm saying, you can give me any numbers when you want.
[00:07:36] And FYI, I'm gonna return a tuple where the first thing has the same lifetime as whatever you gave me for numbers one. Also, if you wanna give me something with a totally different lifetime for numbers two, that's cool. Just FYI I'm going to return something in the second position of the tuple that has the same lifetime as whatever you give me for numbers two.
[00:07:53] In contrast, when I use tick a for everything, I was actually saying that but something a little bit stronger than that, which is I'm saying all of these have the same lifetime, but they don't actually need to have the same lifetime. So I mentioned this because [LAUGH] This is something I have run into before where sometimes I've been accidentally overly strict in my lifetime annotations where I just went through and I was like.
[00:08:13] Yeah, okay, I'll tick a, tick a if you want some lifetime annotations here have a bunch of tick a's. And then later on, I found that I couldn't actually call it passing the things that I wanted to call because I'd been too strict with my lifetime annotations. So, it can't be worth thinking about this.
[00:08:29] Especially if you run into errors where it's saying like, hey, these things need to have the same lifetime but they don't. Sometimes if you take a second look at it, you can realize, you know what, actually they don't all need to be tick a. I can relax that a little bit and say only these two are connected.
[00:08:41] These two are connected, but they don't all have to be exactly the same.