 We have what's new in F-Sharp with Philip, so Philip. Now is it Philip or Phil, or do I have to say it with a British accent? Philip. Philip. I don't know. You could say his Majesty Philip Carter. Of course, like I do normally. Something like that. Yeah. Well, welcome. All right, King Seth. Thank you. Hi, my name's Philip Carter. I'll look in different cameras. And I'm here to talk today about what's new with F-Sharp. Because I work on F-Sharp and other .NET stuff on the F-Sharp and .NET team. So yeah, I want to give a little bit of an overview first. The first is I want to give a slight recap of F-Sharp 4.6, which we released earlier this year and we've been making some improvements on sort of leading up to the F-Sharp 4.7 release. So I think it's good to sort of talk about that sort of stuff right before talking about the brand new stuff. I then want to talk about brand new stuff with F-Sharp 4.7. And then I want to talk about brand new stuff, like even newer than the brand new stuff and F-Sharp preview bits, which we're actually shipping alongside F-Sharp 4.7. This is actually the first time that we're doing this. So it's pretty radical. So F-Sharp 4.6, this was released earlier this year with Visual Studio 2019. However, we've been making incremental improvements especially to the tools since that release. So F-Sharp 4.6 wasn't really kind of this thing that came out and now it's done. It's something that's been continually improved upon. And really the big pieces there were just performance. So what you see here are two issues on our GitHub repository that are related to tooling performance. And interestingly enough, this tooling work is not necessarily in the tools so much as it is in the compiler. And so what I mean by that is the F-Sharp compiler has been around for a while and it's very well optimized for, you know, compiling code, right? You take some code, you run the compiler against it, you get an assembly, you can run that assembly. It's very good at doing that sort of stuff. However, what some people may not necessarily know is that the F-Sharp compiler that we use to actually compile your code is also the same compiler that's hosted inside of Visual Studio, inside of Visual Studio Code, and VS for Mac, that sort of stuff. So, you know, the same code paths that we have internally that take your code in a minute assembly are, you know, the ones that are run when you're asking for things like IntelliSense or tooltips or things like that. And one of the problems that we identified was things that were very highly optimized for, you know, just a single-pass compilation, produce, and assembly were not necessarily optimized in a long-live process, sort of like a server process, you could imagine, inside of tooling. And so as you can see, there's a whole bunch of problems that were here that are all checked off because they're all issues that were fixed. So the end result is just massive performance improvements in all of your tooling, especially if you have really large solutions. So this is something that came out with F-Sharp 4.6, but it's also been continually improving. And so I like to think of F-Sharp 4.6 as this thing that, you know, over the course of multiple releases has just gotten a lot better leading up to the F-Sharp 4.7 release. So the other thing that was sort of mentioned there with F-Sharp 4.6 was the anonymous records feature. And I want to show that in Visual Studio Code just a little bit before I get into the new stuff. So moving over here into Visual Studio Code, which I will point out is using the official F-Sharp plugin known as Ionide, which has about 1.4 million downloads now. It's running F-Sharp 4.6. It's actually the F-Sharp 4.7 compiler, but I'm just showing F-Sharp 4.6 right now. And I'm going to show you a little bit about anonymous records. So for F-Sharp programmers out there who are familiar with records, you know them very well as these types that you can declare up front. They're just, you know, really neat little data holders and, you know, you can do a whole bunch of different stuff with them. And then a lot of F-Sharp programmers are very used to tuples where you can just sort of ad hoc kind of on the fly when you need it, group some stuff together and then, you know, do whatever you want to do with it. But the problem with tuples is, you know, you don't get, you know, as good a tooling support as you do with records, right? You can't rename labels. It's not able to track things as well. And that's just sort of inherent with, you know, tuples being a bit more of a lightweight thing and records kind of being this, okay, well, I declare a type. I'm going to instantiate this type. I'm going to use it in this particular way. And a lot of people want something in between. They want some of the tooling support that you get with records. However, they also want sort of that ad hoc, you know, hey, on the fly, I just want to construct a few things and do some stuff with it. And then later on, they may actually decide, hey, that ad hoc stuff that I constructed, I want to pull that out into a real type declaration. And you can't really do that with tuples today. So that's one of the primary reasons why anonymous records exists. So walking through the code here, we've got this function. It's called getCircleStats. It takes in a radius, which is a float. And you'll notice if I hover over here, there's kind of a big tooltip here and getCircleStats given a radius produces, you know, this little bracket thingy. And that's an anonymous record type. You notice there's the little bracket in the bar. Regular records don't have the bar. Anonymous records do. That's sort of the main way that you distinguish them in syntax. And so I get the area, the diameter, the circumference, just normal mass stuff. And then I construct some stats about the circle that is defined by the radius that I was given. It's got a diameter. It's got an area of the circle, and it's got a circumference. And so when I actually call that code, I can get my little radius value. In this case, it's 3.0. I get the circle stats, and then I can print the values out. So if this were a tuple, if I were to do something like this, there's nothing stopping me from doing something like this. Just sort of returning a tuple and then decomposing the tuple at the call site and then calling it there. But I have to construct the names at the call site every time to get access to stuff. And especially if I have a lot of stuff that has meaningful names that I want to change over time. Maybe I don't like the name. I want to refactor it a little bit. I can't really do that with tuples. In fact, now if I want to refactor this, I can just go ahead and do that right here. I can go rename, and I'll just call that area because area of the circle is a bit redundant. And boom, it automatically changes it. I don't have to go and find the name that I constructed from the tuple that I got back and then also rename that. I can just do it on the fly. So this is pretty much what you can already do with record types. I could have defined a circle stats type as a record up front and then constructed an instance, one of those. But what if I wanted to sort of ad hoc group the radius value with these other values that I have here? Well, again, that sort of thing, I could do something like this. I could go, you know, let the group is, you know, I could tuple, I could go radius, and I could go circle stats, and there we go. This is sort of a typical thing that you would do in F-sharp. But, you know, again, what if I want it, but I want, like, you know, an actual radius value that I could then refactor over time. That's where anonymous records really shine here. So I'll call this more circle stats. And I'm going to take my circle stats value that I have here, and I'm going to use copy and update syntax that you would normally have with a regular record. However, instead of just copying the record into a new, you know, with a new value, I'm going to throw a new field on there. So I'm going to say circle stats with radius equals radius. And now I could print this out. I could go more circle stats dot radius, and there we go. I have that. And that sort of gives you the power of being able to ad hoc group things up like you would with tuples, but also get some of the niceness that you have with records. Now, there's a little bit more that you can do with anonymous records. I want to show just sort of briefly, if you're doing type declarations, there's a bit of code here. But so you may have something like a discriminated union type. You know, an employee could either be an engineer, a manager, or an executive. And so, you know, but I may want to have a bunch of data associated with each of those types. Now, a very common way to do that sort of thing is to do something like this, right? I could have a manager type here. Manager, there we go. I didn't spell it correctly. And so I may want to have a record that holds the data and have, you know, that sort of grow over time. But, you know, if I want to group things up in a way that's convenient, I need to use recursive type declarations, which that's nice if you want to sound like you're really fancy to your coworkers or something, but what it actually means, you have to write more code and you have to sort of declare something as like a big old unit together. Now, I could tuple these up. I could have, you know, like a name is a string and then I could say, you know, reports is an employee list. But then that's a tuple instead of a record type. And what if I want to have a record type? Well, now I have to actually make it, you know, the name manager. Well, with anonymous records, you don't have to do that at all. You'll notice there's less code here. There's no need for a recursive type declaration. And that's because, you know, I've just sort of in line to the record here. So, again, you get sort of the benefit of both worlds here of, you know, having sort of an ad hoc grouping of values, but in this case in a type declaration. And that's pretty powerful for anonymous records. So, moving on, Fsharp 4.6, it's great. We released it. We made some improvements. Some improvements are actually shipping in the VS 16.3 release. But the new stuff is Fsharp 4.7 and the Fsharp preview that we shipped alongside it. Now, this I think I'm a little bit more excited about mostly because we just shipped it yesterday. It includes a few things, mainly language versioning in the compiler itself, which I'll talk about a bit. Implicit yields and some relaxed syntax, which is, I'll go over that a little bit. The high-level bit here is it just makes your code easier to write, sort of less surprises. Things are a bit more consistent with other things in the language. And then Fsharp preview has some new features that I'll show off here. So, I'm going to show off some of this stuff. But instead of VS code, I'm going to hop over to Visual Studio here. The old big IDE. And we'll get going. So, I have a console project here named Fsharp 4.7. This is Donacore project. And I want to sort of demonstrate what implicit yields mean by taking you from a compile error to working code. So, as you may have noticed, there's a red squiggle here. I can generate a sequence with a range expression. I can go, okay, give me from 1 to 10. That's a new sequence. Awesome. Cool. So, what if I just want a sequence comprised of 1, 2, and 3? All right. Well, now it says invalid object sequence or record expression. That's, what? That's pretty weird. Now, you can actually do this in lists and arrays, but you can't do it with sequences, which is kind of weird. In fact, you have to sprinkle this keyword everywhere. This yield keyword. And especially if you're a beginner to the language, this is not very fun. It's not very discoverable. The error message doesn't tell you anything about it. And we could improve the error message, but we figured we might as well improve the language instead of fix the root problem, not necessarily just make the diagnostics a little bit better. We also have this function called get days of week that produces a list. And this same problem actually shows itself in things that are not sequences if you decide to start conditionally generating things. So in this case, I want to generate Monday, Tuesday, Wednesday, Thursday, Friday, but if include weekend is true, I also want to give back Saturday and Sunday. Now, there's just a bunch of stuff here. This is a horrible error message, frankly. Now, again, I could put in a yield, and yes, it turns out, I have to put yields in absolutely every single spot, and that's the only way to get rid of that error message. At least that's the way that things were up until F sharp 4.7. Now, if I open up my project file, you'll notice that I have this lang version property up here, and I've explicitly set it to 4.6, which is the older, well, I shouldn't say older, the one that I just talked about here. So I'm just going to comment that out because this is a new project, and so new projects implicitly use the latest lang version so you don't have to always set it yourself. And if I go back to this file, voila, all of the error messages are gone because all of these yields can now be made implicit. Now, granted, if I'm really in love with these yields, I can add them all back, and the compiler is totally fine with that. So this is backwards compatible. There's no issue with doing that the old way, but we think that a lot of people are going to like doing this the new way once they're in F sharp 4.7. So speaking of doing things a little bit better, we got a wonderful feature that was contributed by one of our community members. His name is Gustavo Leon, and there's a couple of things I want to point out here. So first you can declare, this is how you declare an object in F sharp, and we require an explicit this pointer for members. I could name this anything I want. I could name it this or self or something like that. This is just sort of a convention of the language. Now you'll notice this is grayed out, and that's because I'm not actually using self. I'm not really doing anything recursively with this class. So what typical F sharp programmers would do is they'd say, okay, well, I'm just going to put an underbar there that indicates that it doesn't really matter this pointer. But you had to do a double underbar, and that's because it could perhaps be viewed as a bug in the parser sort of had this little weird quirk where you had to put a double underbar instead of a single underbar, whereas in pretty much everywhere else in the language, if you want to just discard something or say I don't really care what the name is, you can just have a single underbar. So this was fixed by Gustavo Leon, and it's a wonderful little change. It's just kind of one of those things that, you know, it's these little paper cuts that can get you sometimes when you're working in a language, especially if it's a new language, and you're not quite familiar with its idioms. And this is just one of those things that cleans up some of those paper cuts. And the little code fixer here knows to prefix it. Well, in this case, it actually prefix it with underscore. That's one of the options that you have. The code fixer will also actually do the same there. So the tooling is also up to date with that particular feature. Speaking of relaxations, this part of the demo is, actually it's really nothing. It's just looking at the code. And the reason why I think that's important is because if you've been using F-sharp prior to F-sharp 4.7, you know that you would not be able to write this code today. You would have to tab everything over like this. You would have to align this B and this D with this A. And that was the only way that you could get the compiler to actually accept this particular declaration of the constructor that you have here. And frankly, that's just kind of annoying. So we just made it so you got to indent over one. And the same thing applies to static methods in this case. So, again, before, you had to move all of these over so that they were perfectly aligned with the first parameter that you laid out. Now they don't have to be, they just need to have one indentation level over, so that the compiler can understand that these are referring to the method that you're declaring right here. So that's kind of, you know, aside from a whole bunch of bug fixes and more performance improvements, that's kind of what's going on for F-sharp 4.7. But let's talk a little bit about F-sharp preview because that's where things start to get a little bit fancy here. So I'm going to go back to my project file and I'm going to uncomment out this Lang version flag because this is something I'm going to have to actually do now if I want to use preview features. I'm going to clear out 4.6. I'm going to type preview. So save that. Now I can open up this file called nameOf and you'll notice that there's no red squiggles and that's because we've sort of activated the preview mode. So internally, the way that we do things in the compiler is whenever there's a feature that's implemented now, it's associated with a feature flag and then that feature flag is associated with a given release of the language. So in this case, nameOf has the nameOf feature flag and that feature flag is associated with the preview release of the F-sharp compiler. So what that actually means is if you set your Lang version to be preview, you will get everything that's associated with that internally, one of them being nameOf. So going back to the code here, this is just sort of some basic usage that you could, you know, it's pretty self-explanatory, right? I have a function that's called combineLengths. I take two strings, str1 and str2 and I want to dot and get the length of both of them and combine them. Pretty straightforward. I just want to make sure that they're not null before I actually do that and in this case I'm going to raise an argument null exception and then I want to pass the name of the parameter there. So in this case before, I would have to do this or, you know, there we go. I would have to do something like that and if I change the name of the parameter, I would have to know to go back into the string literal and also change it. That you don't have to do if you're on the F-sharp preview anymore. You can just take the name of everything that you're working with and that's pretty great. This is, you know, this has been around in C-sharp for a while and this is something that's been highly requested by the F-sharp community for a number of years. It's extremely powerful if you're doing a lot of logging of parameters and different values and you want to sort of log, you know, this thing which was nested in this thing and nested in this thing and you want to lay it all out and get it into strings. You can refactor with ease and know that you don't have to actually update anything else from there. So just to show a little bit more of what you can do with name of, I have a module with a function and then I have the system namespace up there. So I'm actually taking the name of the namespace. So you can do that if you'd like. I'm taking the name of a module that I declared and I'm taking the name of an explicitly a qualified function, you know, m.f, that's the name of the actual function. It'll take the name and just for kicks I can go let name of, name of and I can take name of, name of itself. Now this is probably not very useful for anyone but, you know, it just happened to be something that was enabled by the feature and so there's kind of no reason not to keep it so we have it and it's fun. So the next one, the next feature that's shipping in the F-sharp preview is opening of static classes. So let me go up right here. So a static class is, you know, this just got a bunch of static methods on it or static members or maybe some constants, things like that. One of the best examples of a static class is the system.math class and historically if you're in F-sharp you would have to go math. You know, you would have to explicitly qualify math.whatever you want to use to be able to actually use it. But now you can just actually open this thing and, you know, if you were to do this in F-sharp 4.7 or F-sharp 4.6 you did not have the preview turned on. You would actually get an error saying that there is no namespace called system.math and that's because it's a class, it's not a namespace. And so what that means is I could just call sine of pi rather than math.sine of math.pi. It's the sort of thing that is really handy if you're working with the math namespace and other libraries that do this sort of thing where they put this kind of functionality behind static classes. And this is also helpful for F-sharp programmers who want to create DSLs that use method overloads just like you can do a little bit in C-sharp. And you can actually declare those in F-sharp today because as it turns out a static class it's not really like a real thing. It's an abstract sealed class in .NET. And so you just create a type that is both abstract and sealed and you give it some static members. In this case I gave it L, M, N, O and P. And then you can open this class when you have the feature enabled and you can just call them like that. I don't have to explicitly specify mystaticclass.L of mystaticclass.M of mystaticclass and so on. This is something that we're pretty excited about especially with some of the focus on working with machine learning frameworks that we've been doing lately because a lot of these frameworks for .NET are using static classes to sort of pack these method overloads behind there but have it be sort of a functional interface. And this will play very nicely with that sort of stuff in the future. So that just about rounds out F-sharp 4.7 and the F-sharp preview. So as a quick summary here, F-sharp 4.6 we shipped anonymous records. We've made improvements to those and the tooling for them over time. It works pretty much everywhere and there's been tons of performance improvements in the compiler and the tools since it was released all the way up until now and also including this release with F-sharp 4.7. F-sharp 4.7, once I fix the spelling error here I like to think of it it just sort of makes things easier for you as a F-sharp programmer. It cleans up a lot of little things and especially if you're using these yields a lot like if you're writing web-sharper or Fable code which uses lists and as sort of like an HTML style DSL something like that. This makes it a lot easier and then the lang version support allows you to sort of bump up to a preview try some stuff out, give us a lot of feedback get access to those features wait earlier before they actually ship and then F-sharp preview is all about features right now building features and shipping features starting now pretty much all the way until the middle of next year before we start stabilizing for the .NET 5 release. So if you want to get started with F-sharp 4.7 there's just a single link you got to go to you just go to aka.ms slash F-sharp home this takes us to the F-sharp home page on the .NET website and if you go there there's just a big old button that says get started it'll take you to download the latest .NET SDK and you can do that you'll have F-sharp 4.7 already available and then you'll be able to get off and go running with it