 It's no secret that f-sharp works quite a bit differently than c-sharp or visual basic. It's a It's multi-paradigm, but let's face it. The the main paradigm of it is drastically different cls compliance does Aid interop quite a bit it as long as something is cls compliant It should work across any cls compliant language f-sharp is so anything that is cls compliant from c-sharp will be callable from f-sharp The experience Is not good any of you who have had to work as an f-sharp programmer With c-sharp or visual basic libraries really knows exactly what i'm talking about You might be able to do functional programming in your own code But anytime you have to hook into the other stuff it's a massive paradigm change What i want to show off is one way to help with this Whether you're a library developer looking to offer More natural feeling f-sharp support or you're somebody who just has to work with libraries that Don't do this and you're trying to make things a little bit better for yourself or your team There is a way to overload functions in f-sharp If you're an experienced f-sharp developer, you know that the normal way functions work is through being generic as generic as possible The type will resolve to Whatever the motion generic thing it can For whatever the expression that you've bound is And if you try to tie in to C-sharp or visual basic code This doesn't Work that great. Let me show you what i mean We're going to just have a contrived example of write and We're going to just say that it directly calls console write and Puts the text there As you can see it's not happy about it. It's complaining about how it can't resolve what type is and Sure enough it does have its a-tech Which is your standard generic parameter type But it just can't figure out what write to call You can work around this for some stuff by saying object instead and That works in this instance because console dot write does support object parameters It's a little less than ideal of course because Some of those writes are actually optimized for specific types, which is why there's so many overloads of that And You just won't be using them at all That's not great Now this unfortunately is one of those rare cases where this technique doesn't work I will say from my own experiences I never encountered a situation where this approach doesn't work until trying to record this video This is the second time now. I'm recording it because Our original plan just didn't work But I do have a Another contrived example where this does work. It's not What I'm doing directly here is not going to be practical But it will show you how this approach works and I will explain everything that's going on so we're going to have a Just foo and we're gonna give it two generic parameters And I'm going to explicitly declare the types on these Just so that you can see that there's definitely no trickery going on That it is going to enforce these and if it cannot enforce these it is going to Complain about it. It is going to throw an error that it cannot resolve um And to show you kind of what I mean, let's just say Uh a plus three And you can well in this case, it's a warning But either way, you know the the compiler will actually complain about this That it's saying that because three is an inch it the entire thing has to resolve to ends Um, that's not what we want We want this to resolve I dynamically or at least something that feels dynamically So we're going to do different things based on what the type of a and b are We're not going to deal with, uh, the return type That the approach for that dealing with that isn't any different. It's just not something I wanted to deal with um So the first step here is to define an inline function Uh, I've taken to always declaring these as privates Just because they're The syntax we're calling it is not pleasant. Uh, this is essentially our Syntactic sugar around this function that we're defining now We need to give it, uh An a hat a b hat and a c hat parameter, uh, just because we have the a b and c there Oh, uh, I also need to give it a name. That's kind of important Again, this is just a convention that I've gotten taken to much like declaring it private Uh, I just keep the same name but with an underscore in front of it. You can do whatever you'd like It really doesn't matter. That's just a convention that I've taken to We're keeping the parameters for here If a and b are the same type you can alleviate this by just doing this You'll you should be able to figure the rest of this out as we go along but Yeah So what we then do is Where and we're going to give it a explicit condition on a And I am that's not where is it. It's when and then we're going to say that, uh Well, what this is doing what I'm setting up here is saying we're going to look for something on whatever the a hat parameter is So whatever this type resolves to we're going to look for this thing on that And we're going to specifically look for a static Number and Then we have to give it a name and this name is important This name is going to be explicitly the name of the thing we are looking for. So this has to be correct This matters And then we are going to give it the signature of foo now I'm just doing contrived stuff. Normally you would want to look up what the signature of the Member you're calling Um This is typically going to be a method So just find out what the method signature is in my instance since I'm Going to be defining that after the fact Uh I already know What this that signature is going to be if you're having trouble figuring that out pause now define the methods And then just see what the signatures are and copy that signature into here But since I already know we're going to take an a an a hat and a b hat And because these are on a method These are going to be tupled. That's why I'm using the star here Rather than the normal function passing Now we have that I can close this generic off and Declare the parameters which we're Just I keep to using the same parameters. It just helps with readability And then we need to define the function Um Well assign the function bind it And we largely just copy this whole thing Why are you complaining? I'm not sure if there's an issue there There is oh, yes, there is this needs to be There we go Okay, now we bind into here. So this whole thing largely gets copied. We're going to have the a hat and we're going to Do the static member foo And now we pass in those parameters that we declared So what is going on here basically is that we're saying that We're going to be working with these three generic parameters On whatever the a hat parameter is We are going to look for a static member that is explicitly called foo And has this type signature We are then going to call That static member foo with that type signature that was found on the a hat parameter With the tupled arguments a and b Hopefully you follow I understand this whole thing is Not Normal code you write So then we're going to call this From here remember this is basically the thing giving us syntactic sugar over this monstrosity And Since we're being explicit about well In most cases you can just do the underbar thing of I don't care figure it out And then just give it the parameters a and b and You see basically everything works out just fine except since it's It's at this point. It's doing what it's supposed to we're not done yet But I still want to explain the error here so that you can kind of get an idea of how this is working But we're not we're not done yet What's going on is that it's Trying to resolve these parameters and can't So what f sharp does is it defaults to obj? Now you can see here that the a tick parameter is Well, I just said resolved to obj And as I was explaining here The first parameter which is a taken this instance the which maps to the a hat Within a hat it's looking for the static member foo and you can see that it's complaining about Actually might be clipping on for you guys a little bit But what it's saying is that It can't find a method foo On the type obj Which makes sense. That's not something obj has defined um If The types you are working with Have this defined for it. You should be good Uh, you may need to explicitly declare what those types are in any of these and again I've set this up so that it maps exactly But you can just be explicit about a type like We're going to say look for foo within In 32 and of course it's not going to find it But you can see here that the air message changed a little bit that it's saying that the type in 32 does not support the member foo Make sense it doesn't we're going to change that back and Here's what you do now if You're trying to overload on something that is from a static class Or you're going to do the bizarre thing that i'm about to do where you're going to define Very random and unrelated stuff to do based on what the type is You need to define an additional type now. I have taken to calling this binder That's just convention. You're not being explicit here Just know that you need to copy this name into one of the new generic type parameters We're going to be adding but you can call this whatever you want This has to have the same visibility as this though So if this is private, this has to be private If this is public, this has to be public. They have to be the same Uh, so then We're not going to do a default constructor. It's fine. We're basically treating this as a static class. We just Can't define the static class Then we're going to define the static member foo And remember this is an explicit thing. So these names have to match exactly It's not going to resolve them based on these the type signature It is going to specifically look for the name and then the type signature The name has to match Or then going to give it the arguments and let's do I don't know integer well a integer and the Integer and We're not going to say what to return because quite frankly The type system can figure the rest of that out You can treat this exactly as you would treat any F sharp code normally You know, you might need to define one or both of the type parameters but I can probably leave these out for what i'm going to do a times b The divided by three And yeah, it it resolved those just because three is so explicit that the rest have to be the int32 type But you'll notice this is still complaining And the reason for that is nothing about this knows to look inside of this type So what we have to do is add another generic parameter And what the community is taken to is to define at the start of this another generic parameter called t hat And the reason for that is it's not really a parameter of the function that we're defining It's Just another where to look for it So we have t hat there and we need to add it as well to here and here and In in this part Sometimes Autocomplete tries to help you out and does the wrong thing. So you may need to fight that a little bit But now what we're saying is that basically the same thing We have a static member foo with this signature, but you can look for it on The t hat or the a hat parameters And now we're going to add a new one You cannot Let it try to resolve that it just it doesn't make any progress But you can specifically add that type And it will resolve that Now because there's only one foo defined It is giving a little warning about how it's less generic than we're declaring it as Because we're declaring it as generic parameters and it only resolves To this specific one, which is of course defined for it And that's the same thing because we didn't declare these explicitly than they're considered generic. Yeah Uh, we'll shut that one up by telling it that these are specifically in This one it'll complain as long as there is only a single member defined here and Rightfully so if you're doing all of this just for a single one Just put this code here But what this boilerplate I guess this Magic going on here allows us to do is define a new one Uh, let's say that works for a car and a car And we're going to do I don't know what are we going to do with the cars Concatenate them which in f-sharp is actually a bit of a pain It's going to complain a little bit, right? Trying to type obj and That might not be good. Oh, um, if I remember right this has to be inline. So if we change that Okay, I forgot about that that is important. Um The inline nature of this is extremely important f-sharp type resolution is sophisticated. That's Sophistication is partially why we're able to abuse it the way that we are here But there are two general approaches it takes when resolving type parameters The normal approach is to dynamically resolve them at runtime That doesn't work with this trickery You have to resolve them at compile time And the only way to do that is to inline it So when both of these are inlined What it'll what winds up happening is anytime you call foo with these parameters It looks for whatever Member matches and just puts that member in its place These calls They disappear That's what allows this to work So if we We're still gonna need to print So we're just going to instead call foo and I don't know two and three And I don't know if that's going to Because you're not compatible with that I'm not an extensive f-sharp programmer. So bear with me. I understand how this works I understand a lot about the language, but I regularly forget syntax stuff This isn't the environment I normally work in So let's just call this I don't know a foo two and three and of course we get an int out here because it's just Flat out placing that one in its place And another one be is foo and we need to give this one character So we're going to say I don't know a and one And of course we get a string because that's what the output of this one is So now if we print I don't know can we just do this is this a thing? No, because it's I don't remember how to and I think if we say digit Let's not move that okay, that's Yes, and Then it's s. I think for strings and we do that And you all check out Now if I run this we should get the output of each of these independently even though we're calling the same function Just because I'm determined to see if I understand f-sharp correctly. Can I do that? I can't no no, I can't Uh If I wrap that I can now We're gonna run this and we should get the output of each of these independently Even though this is technically the same function. Just we're calling it with different types And we do I'm not checking the math on that but that one's definitely correct and regardless it's clearly calling different different operations Now you can implement something similar by using obj as your type parameter for everything and then Pattern matching on it and doing different things based on what the selected type is uh This approach is faster for what is hopefully obvious This is happening at compile time and it's just placing the appropriate thing in Based on the type parameter Uh, which means there's no run time overhead with this approach The other thing though is if your type parameter is obj you never get an error message at compile time because Everything is obj Not so true with modern net versions because ref structs violate that but basically everything is obj and Everything is a valid type So let's pass in Oh, I don't I don't need to do that. This isn't going to work. Anyways, so let's just do Uh foo on a string. Hello. And then again on uh Just a character for the exclamation point And oh my error message is clipping um It's clipping off the screen, which means you guys can't see that so I Will take a screenshot of it and put it in post So that you guys can see this but It's actually explicitly telling us that one of the type parameters and it is clear which one Uh Cannot work because it's not compatible with and it's naming the other two type parameters that it could be String is obviously the one that's not working because This matches car which of course matches this one So string is not matching and it's saying the two types for a that it could be Now we can work around this and magically make it work if we step member foo a for string b for car And we take an a and come cat get hash code to string Because i'm doing bizarre contrived stuff and I just want to make this do something now If we print in and I think the hash code of a character is just the Number uh its code point um I'm pretty sure that's just the result of casting it to a integer uh Probably just that but uh this clearly resolves now and if we run this again Okay, that's not the code point I I know that's definitely not the code point of an exclamation point. So interesting But we're still resolving all of these correctly So just to try to add in some something to confuse this to show you that it doesn't get confused We're going to add another one Uh that takes a int 30 I don't need to capitalize that in 32 and takes a car So we're intermixing these types And we're going to do Uh, I don't know a I'm going to convert that to a string Uh, who's we're going to do a Times four plus seven two string And we're going to cat Uh Be all of these still check out. It's not complaining still And we're going to add another one of these and this is a string as well. So we'll just do that Uh who and what did I say an integer and then a car? Yes So I don't know. Let's give it 42 T And that one checks out So now if we run this again You are going right Okay, that was weird But either way you see that everything is still working it it's weird boilerplate and I'm actually rather amazed this works even though I understand why this works It's still amazing to me that this works at all It's definitely abusing f-sharp's type resolution algorithms Um But yeah, there's no performance overhead to this and you get overloading You can use this and I primarily use this for Creating very natural f-sharp feeling Bindings to code that was written in c-sharp or visual basic You can take all the overloads that you wrote and Still make them work and still get great error messages and Yeah, it's a bizarre system. I highly doubt this is something you would stumble upon accidentally trying to get this to work But it works and it works well um That's it for this one. I do have some more tricks Dealing with abusing f-sharp's type system Uh, the one I'm going to cover next definitely builds on top of this. So Hopefully you understand what's going on. If not, leave a message down in the comments and I'll try to explain it to you The next one is on overloading operators. It's not done It's mostly done the same way but it it's I'll cover that in the next video Until then have a good one