hey YouTube in this one I want to talk about these two characters ref option T and option ref T and what the difference is and when and why you might choose to use one versus the other in let's say a function signature now I'll spoil it right off the bat I'm going to be arguing that you should never choose ref option T and you should always choose option ref T and I'll explain why so let's get into it so let's say that we have a struct called Data and we don't really know what's in there but let's just assume that it's arbitrarily large and note that it does not Implement copy or clone so it's just some mystery data that we can only move around and only has one API which is a public method called crunch which takes the data crunches it and gives us back an integer so keep this struct in mind this is a type I'm going to be using throughout this video now let's say that I'm creating another type called widget that maybe has a data inside of it so the most natural way to express that is just by having a field of type option data and let's say that I want to write an accessor that lets users of widget look at my data if I have it so there's two different ways that you might be tempted to write an accessor or getter like this the first one is slightly more natural it's a method called Data a that just returns a reference to the option data that's stored inside widget now there's another version of the same getter that you could write that I'm going to call data B that doesn't return a reference to an option it returns an option reference and you see that the implementation is slightly different I have to use this as ref method on my option which converts it from a reference to an option to an optional reference so this is two different approaches to pretty much the same API and so which one's better well I already spoiled what I think but take a moment to think about what you think what are these two different function signatures saying to the caller what are the different restrictions that they place on the collar and what restrictions do they place on you as the author of widget so in my opinion the difference between these two function signatures becomes much more obvious if you go ahead and add mute to everything suddenly there's a Salient difference between returning a mutable reference to an option versus an optional mutable reference in this top one I'm saying hey I'm storing my data in an option and here is mutable access to that option that I'm using to store my data and you the caller can do whatever you want with it you can set it to none so that I no longer have data or you can also get at the underlying data and mutate it for this bottom one what the caller can do is slightly more restricted they can mutate my data but they can't change whether or not I have data because I'm not saying here's a reference to the way that I'm storing my data I'm just saying here's a reference to my data if I have any and so there is an actual semantic difference between these two and so there actually are valid reasons why you would choose one of these over the other depending on how much power you're trying to give your caller although I do want to point out that if you are just returning a mutable reference to the entire option that holds your data you might as well just make it Pub so that your caller can just access it directly so I hope that adding mute kind of helps clarify your intuition about the difference between these two things and I'm going to argue that even when we remove mute that difference in the meaning of these two function signatures remains data a is saying I am storing my data in an option and here is a reference to that option data B is saying I may or may not have some data but if I do here's a reference to it now unlike with the mute example where I pointed out that there may or may not be a good reason to use one over the other because they actually have semantic differences I'm going to argue that data a never makes sense in other words using an immutable reference to an option in an API that you're writing never makes sense it's never better than using an optional reference and is frequently worse by the way I do want to mention for completeness that references to options show up all the time in your rust code for example anytime you call a method on an option that takes a ref self you're using an immutable reference to that option so I'm not saying this type shall never appear in the normal flow of your rust code in fact it very likely will I'm just saying that you shouldn't use it as a tool for designing apis so let's see why so to help illustrate this let's imagine a call site of these methods so I have a widget that's just defaulted and I'm calling both methods and storing them into a and b respectively and I have the types annotated here just so we can remember which one is which now first off these are going to be equivalent in terms of whether the option has anything in it or not in other words this assert is always going to succeed at least with the way that we've implemented them at the moment and I point this out because you might think that having an actual reference to the option that the widget is using like we have an A might give us some interesting visibility into that somehow like we had with the mute example where we could actually change what was in the option but you can't do that with an immutable option so all you can do is ask questions like is sum but what I'm pointing out here is we can also just ask B if it's sum so having an actual reference to the option that's inside the widget doesn't actually give us anything that we couldn't also do with an optional reference so we don't gain anything by having a reference to the actual option that widget is using but we do lose things for example let's try and get at the underlying data because I want to call the crunch method on it so all I have to do is call map on a to get at the inner data and then call Crunch on that right well the rust compiler disagrees I get this error that I can't move out of star a which is behind a shared reference and you're probably familiar with this error if you use a lot of options in Rust a lot of times you want to call map on an option but map actually moves out of the source option and so if it's an option that you're not allowed to move out of like one that you only have through a shared reference you have to first convert it into your own option that you can move out of and the way you do that is with asref and you can see that the error even suggests that so we better fix it if we just insert azref here this compile is just fine now what about crunch B well this just works out of the box because we are allowed to move out of B Because if you recall we already called as ref inside the implementation of data B so B is just a value in this scope that we have ownership over and we can move out of it and in fact option ref data implements copy so we can even keep using B after this line if we want to so in order to get to the underlying data inside of a we have to use as ref anyway so everywhere that we've called Data a now at every call site we also have to call as ref if we want to get at the underlying data whereas for data B we already took care of that for you the caller doesn't need to worry about it so data B is just a more convenient easier to use API so that's how option ref T can make a call site prettier than rev option t now there's another argument that I kind of hinted at earlier but I glossed over a little bit which is the data B here provides better encapsulation and more implementation flexibility than data a does for example you remember how I said data might be arbitrarily large maybe one day we're profiling and we discover that storing data directly inside widget is having a negative performance impact maybe we're moving lots of widgets around and having the actual data contained inside the widget is just getting to be too much so we decide to put data on the Heap instead and have widget just hold a pointer to it using box so now we've wrapped our data in a box and immediately we have to go change the signature of data a because we no longer have an option data to return a reference to we actually have to return a reference to our option box data now and this isn't just annoying to have to go change your function signature this might actually break code that was calling data a before for example the previous code snippet that explicitly spelled out the type of a as reference to option data that call site no longer compiles we have to go fix that one too so this is actually a breaking API change that you have to make to widget for what should just be tweaking an implementation detail so this provides no encapsulation for you and the details of how exactly you've chosen to store your data data B on the other hand we do still have to change the implementation and I'm using the as draf method to get us there this uses the draf trait on the underlying box to give us an optional reference to the data that it points to but the important thing to note here is that I did not have to change the signature so no one except me has to know that I even made this change all of my call sites continue to work exactly how they did and this is the essence of encapsulation I want to be able to make changes like this to widget without having this ripple effect throughout my code base where I have to go fix tons of stuff because my API leaked too many implementation details about how exactly I was storing my data and this isn't the only type of example of this just for another one real quick let's say that something in my business logic changed I no longer want to just always let the caller see my data if I have it I also want to check some other condition first before telling the caller yes I have data for you to look at so for data B this is Trivial all you have to do is add a filter to the option that you're about to return with your extra business logic in it to decide whether the caller should see your data or not but for data a filtering this option further based on some predicate is impossible if you're returning a reference to an option box data that you own there's no reasonable way to apply filtering on it before returning it to the caller and if you don't believe me try to get it to work yourself I bet you could come up with something that compiles but not something that anyone should realistically ever write so far I've only talked about ref option T versus option ref t as return types so let's take a moment to look at them as parameter types so here I have do something a which takes a ref option data and do something B which takes an option ref data now the same intuition we've been building for the difference between these two things holds here as well just sort of in Reverse so do something a is telling the caller give me a reference to the option that you are using to store your data so it forces the caller to be holding their data in an option which like why if do something a wants access to the data it's going to have to call asref anyway inside of the implementation and besides that there's just no reason to force the caller to have their data inside of an option do something B allows the caller to have their data wherever and just stick a reference to it inside of an option and it also gives the caller the ability to do things like filter that option just like we did inside of our database accessor so do something B just gives you more flexibility and to see it in action let's look at an example call site so let's say that I have some data that I get somehow and note that it's not an option data it's just some data that I actually have and now I want to call both of these functions with it now notice that I actually had to call do something a second because this call is going to move out of my data because I have to move it into the option that do something a is asking me for so I couldn't have put it first because then I wouldn't be able to call do something B afterward do something B is no problem I just create a new Option using a reference to my data now keep in mind that do something a only works here at all because I'm allowed to move out of data if data was instead something else that I'm not allowed to move out of like a shared reference it's no longer possible to call do something a with this data I can't even do something nasty like clone it into a temporary option because data doesn't Implement clone so I literally cannot call this function using this data do something B doesn't even break a sweat here all you do is remove the Ampersand although you actually don't even have to so do something B is useful regardless of whether I actually have my data in an option or not whereas do something a if I don't have my data in the exact right shape at the call site it might be impossible to call which if you ask me is not a very useful function so once again option ref T is a better choice for parameter types than ref option t so now let's look at the data layout in memory of option T ref option T and option ref t partly because it supports my argument about using option ref T wherever you can but mostly just because it's kind of fun so as a disclaimer rust itself does not actually guarantee that much about how these values are laid out in memory so take all of this with the tiniest grain of salt but I'm going to be showing how things tend to work in practice so here I have two values of type option i32 the top one is none and the bottom one is sum 42. so you can see that for both of these I have a byte at the front that says which option variant is active none or some in the nun case it's zero and in the sum case it's one now these bytes are followed by some padding so that my 32-bit integer payload is correctly aligned and that padding is followed by the payload so in the none case it's just grayed out we don't know what's in there it's probably garbage in the sum case it has the integer value 42 in it now Along Comes ref option i32 so a reference in Rust is the size of a pointer on your architecture in this case I'm assuming 64-bit so this pointer is 8 bytes wide and it's pointing directly at the option specifically at the beginning of the option where the enum discriminant byte is now I'm going to show option ref i32 but before I do take a moment and see if you can guess what it's going to look like here it is is this what you expected if you expected a discriminant bite in red followed by some padding followed by a pointer value that would be a reasonable guess but it's actually wrong the rust compiler is smarter than that the rest compiler knows that references can never be null in other words a valid reference can never have a bit pattern that's all zeros and that includes the ref i32 inside of this option so the rest compiler says well all zeros can never be a valid reference so instead of adding an extra byte to track whether this is none or some I'll just use all zeros to mean none for option ref i32 if I see an option refi 32 and it's all zeros I'll just know that that means it's none this is called a niche optimization and the rest compiler is very smart and does a lot of these things for you and it's really really cool and it's a cool topic that you should go learn a lot about if this Peaks your interest but the takeaway here is that option ref i32 has no space overhead over just a regular reference it's essentially just a reference that can also be null and mostly I just think this is really cool and I wanted to mention it the last thing I want to talk about in the debate between ref option T and option ref T is what if you're inside a function where you really do need an option t with ownership like take this function for example it's called I need ownership and it's taking in an option ref i32 but inside it needs an option i32 so wouldn't this be a good example of a time when it would make sense to take a parameter of type ref option i32 I would still say no because that imposes all of the problems on the caller that we talked about before and if you need an option i-32 it's actually really easy to convert an option ref i32 into an option i32 and there's more than one way to do it one way is to map over the contained ref i32 using the two owned trait the two owned trait usually just ends up calling clone on the reference that you give it but it's a little bit more General than that in particular if you give it something like a reference to a slice it'll convert that into a VEC another way of doing this that I prefer because it's shorter is just calling the cloned method the cloned method exists for option ref T where T is sized and it just literally calls clone on the underlying reference which is usually just fine the only downside over two owned is that like I said two owned is slightly more General and that it'll do stuff like convert slices to VEC whereas dot cloned will simply fail to compile for slices lastly if your type also implements copy on top of Clone you can just use the copied method which just calls copy on the underlying reference to give you an owned value using the copy trait and this one's my favorite I'll use copied if I can get away with it I'll use cloned if my type doesn't Implement copy and I'll use two owned if I'm doing something fancy or if I'm writing a generic function and I want it to work on dynamically sized types like slices but even better than all of those things we just talked about if I need ownership over an option i32 inside my function why don't I just say that in the parameter type then the caller can figure out how best to get me one maybe they have one sitting around that they don't mind moving out of into my function or maybe they know they need to clone something to make it happen but either way I like this function signature much better because it's more honest about what this function needs it needs an owned option i32 so there's no sense in lying about that by taking a reference so that's all I've got for today I hope you have a better intuition for the difference between ref option T and option ref t and I hope I've helped convince you that ref option T that is an immutable reference to an option only makes your code harder to work with and your API is less useful that being said I certainly haven't seen every use case Under the Sun and if you have a valid use case for an immutable reference to an option I'd love to hear about it leave me a comment if you haven't already aside from that I really appreciate your time thanks for watching and I hope to see you in the next one