Change your habits: Modern techniques for modern C# - Bill Wagner

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Bill Wagner is a developer of the C# language (Wikipedia))

Tuplet assignment

public Point(double x, double y)
{
    this.x = x;
    this.y = y;
    this.distance = default;
}

is equivalent to:

public Point(double x, double y) {
    (this.x, this.y, distance) = (x, y, default);
}

This makes sense for two, or three fields, for more becomes less readable.

Tuplet comparison (lets pretend we can compare double values this way)

public static bool IsEqual(Point left, Point right)
{
    return (left.X == right.X) && (left.Y == right.Y);
}

Can become:

public static bool IsEqual(Point left, Point right)
{
    return (left.X, left.Y) == (right.X, right.Y);
}

Swap variables with tuplets:

public void Swap() {
    var tmp = X;
    X = Y;
    Y = tmp;
}

Can become:

public void Swap() {
    (Y,X) = (X,Y);
}

Readonly structs

Annotating readonly on a struct makes sure the compiler does not copy the value of a struct. It has some performance benefits and pitfalls.

Pattern matching:

public bool Equals (object? obj)
{
    if (obj is Point)
    {
        var otherPt = (Point) obj;
        return this == otherPt;
    } else {
        return false;
    }
}

Can become:

public bool Equals (object? obj) {
    return (obj is Point otherPt) ?
        this == otherPt : false;
}

Throwing exceptions using a null coalescing operator

public void SetName (string name) {
    this._name = name ??
        throw new ArgumentNullException(nameof(name),
        "${nameof(name)} cannot be null");
}

Throw null exceptions when not assigning something, assign to a discard. Bill would like this kind of behavior to be the future standard way of doing this.

public void LogMessage (string message) {
    _ = message ??
        throw new ArgumentNullException(nameof(message),
        "${nameof(message)} cannot be null");

    // do something with message..
}

Turbo switching: Pattern matching + tuples + switch The example given is a bit complex to summarize. I think an easier example is given in this blog post

static State ChangeState(State current, Transition transition, bool hasKey) =>
    (current, transition, hasKey) switch
    {
        (Opened, Close,  _)    => Closed,
        (Closed, Open,   _)    => Opened,
        (Closed, Lock,   true) => Locked,
        (Locked, Unlock, true) => Closed,
        _ => throw new InvalidOperationException($"Invalid transition")
    };

Date and time math: Don't do it yourself. Use TimeSpan and DateTime for all your adding and subtracting needs, because dates are a mess.

πŸ‘οΈŽ︎ 31 πŸ‘€οΈŽ︎ u/keesbeemsterkaas πŸ“…οΈŽ︎ Mar 08 2020 πŸ—«︎ replies

Good video, I think I'll start using a few of those.

Timestamps for others, if you want to skip to the main points:

πŸ‘οΈŽ︎ 21 πŸ‘€οΈŽ︎ u/IchLerneDeutsch πŸ“…οΈŽ︎ Mar 08 2020 πŸ—«︎ replies

TL;DR

New Habits

πŸ‘οΈŽ︎ 12 πŸ‘€οΈŽ︎ u/sl-remy πŸ“…οΈŽ︎ Mar 07 2020 πŸ—«︎ replies

Some interesting stuff here. I like the tuple swap too.

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/TheDevilsAdvokaat πŸ“…οΈŽ︎ Mar 08 2020 πŸ—«︎ replies

Thanks for sharing, that was pretty useful, I loved the pattern matching with the switch statement, really amazing, the explanation about it starts at 38:00 in the video, it was gold!

πŸ‘οΈŽ︎ 3 πŸ‘€οΈŽ︎ u/heavykick89 πŸ“…οΈŽ︎ Mar 08 2020 πŸ—«︎ replies

I saw this a couple of days ago. It’s a great lecture.

πŸ‘οΈŽ︎ 1 πŸ‘€οΈŽ︎ u/moi2388 πŸ“…οΈŽ︎ Mar 08 2020 πŸ—«︎ replies

!arweavethis

πŸ‘οΈŽ︎ 1 πŸ‘€οΈŽ︎ u/Both_Writer πŸ“…οΈŽ︎ Mar 09 2020 πŸ—«︎ replies
Captions
so good afternoon I'm bill Wagner and this Twitter handle on the slide so you can contact me afterwards any way you want it's also my github handle so with any other questions go ahead and go to the C sharp Docs repo and you can pose questions and ask issues there so the title of this I chose rather deliberately so we're what I want to have happen out of this talk so I'm going to show you a variety of different things that you can do with the new features we've added into the c-sharp language that should make you more productive and should increase the quality and the clarity of the code that you write so what that does mean is as I start each of the demos and I show some code that looks like it could have been written a few years ago I don't want you to go back and go oh no I've got to rewrite all this because that codes probably been tested it certainly works it's certainly in a good spot but as we've been involving the language we wanted to make that a little better so the idea behind this is if you think about computer languages programming languages they are all opinionated they were designed by people who thought certain things and certain techniques and certain goals were important other things not so much so at the time of their design in every instance they come up with ideas that say we believe this is the way you should write software and this is how you should do it and they made those things easy but if you look at the arc of computer programming languages they usually take a long time to get get a lot of adoption and once they do have a lot of adoption they take a long time to stay in the industry because there is so much code out there that is using that language so every programming language expresses opinions in a lot of ways the programming languages will have intentional opinions we think this is a good way to solve these kinds of problems some languages and probably every language in some way or other has ax opinions I know we didn't think about that and now it's here right I mean every language does so I'm not gonna try to pick on any in particular here language expresses opinions by making some things easier and by making other things harder and this is the thing that we're really wrestling with and trying to do is we continue to evolve the c-sharp language if you look at the arc of our modern more recent language releases we have learned a lot of things as in industry since the initial design of c-sharp in round 1999-2000 so we want to make it easier to create better software using the techniques people are recommending in general in 2020 and beyond that is the only way the language will stay relevant it's still gonna be an object-oriented language that is where its roots are we do not intend to take any features away because that would just be unwise there's too much code out there but we also have recognized and continue to recognize that things we may have thought were good ideas or may have thought were now this is easy enough in 99 or 2000 isn't easy enough anymore so we want to make that better so we are doing a lot of things to make it easier to work with different kinds of data one of the things that we learned you know that if I look at the arc of history in computer languages the advent of Java and c-sharp was because the industry finally realized after C and C++ and other languages like that that managing allocated memory was a whole lot harder than anybody thought it was see ya malloc and free how hard could it be right how many different bugs were because of that C++ knew and delete and different kinds of new and delete and so on and smart pointers and so on better still a problem wait to see sharp in Java these things are easier but now when you look there are still things that we did not make as easy as we could have from things that we've now learned as an industry with the kinds of programs that we write now so it's important to start to add those features so with that introduction I'm really gonna spend the rest of the time looking at code and talking about the way we wrote things and the recommendations we had and how we would go about doing that now and different things we've added to the language that we want you to explore and to start to adopt as habits every time that you're working so the first thing we're going to learn is if you work in the area of computer languages the only demos you're allowed to do involve points and a person class because they're easy to explain I don't have to explain the domain we know what a 2d point looks like we know what a person object should be and points let us work with value types very nice and easily and person objects let us work with reference types so I'm gonna start with some things in our basic point class I'm gonna shrink this down a little bit they after changing are so I've got x and y I can public gather a private setter I know I can simplify some of this and I will get to a fair amount of it I have a design decision that I want to calculate the distance but I want to calculate it lazily so I've got a nullable double to store the distance and I've got a property that retrieves the distance calculating it if I need to I've got a constructor I've got an operator equals operator not equals because of that I have to override equals and we've got a gitch hashcode that I'm not gonna debate whether that's a good get hash code or not but it's keeping the compiler happy and then just because I want to make sure this is good for beginners I'm going to show a neat little trick to get you through that entry level programming interview where everybody says I want you to swap these values all right and you know anyone has their first programming interview it's like x equals y y equals x oh you got it wrong you've never had to write that code again but just in case you do I'm going to show you a neat trick so a c-sharp 7 and we added tuples and we added them just so that it was an easy way not to have to write a class or a struct every time he wanted to hold more than one value right because that was encouraging behavior that we didn't like right we want to keep these things together but then I got to write a class I got to put all these things in there I'm gonna define these methods and now I suddenly got two pages of code just for something you can make a lot of sense so we put in tuples turns out once you have these there's some really neat fun tricks you can do so let's start here with this constructor it looks like a lot of constructors you would write for any of the types that you create I've got a set of private fields I've got a set of arguments that come in and I'm gonna set each private feel to that argument and depending on how many fields you have you get this different life this is this this is that that's that the other thing well let's just write this in a real simple way now that I've got two pools and I'm gonna go X right X comma Y comma distance equals and let's change that to this that X because I gave them the same same casing is that Y and that's going to equal X comma y comma distance comma default and then I don't need these lines okay so I've just made one assignment that says let's really temporarily just create this tuple that has the private fields that I want to initialize on the left side and on the right side let's just create another tuple that's got the arguments I want to pass to it okay this is one of the ones we do not have a code fix or refactoring for and there are a couple reasons for it this looks good because it's got a total of three variables and they're generally small in practice when I'm writing code and when I'm looking at different things I will use this technique just about all the time with two arguments I will often use it with three depending on the length of the variable names four starts to look dumb so I usually don't do that and then I would go back to separate statements so if we were gonna add a refactoring for this and there's a called possible community project to do it we would want to be able to go through go both ways to be able to say take these separate statements and make it into a tuple assignment take this tuple assignment make it back into separate statements because classes have a way of growing fields occasionally over time so there's that one well now as soon as you see that then you start to look at something and you go this operator equal equal looks like it should do something a lot like that and if you've ever done code reviews you may often see depending on the thoroughness of your tests that sometimes in one of these you might miss a left and a right or you might miss the property names because we we copied and pasted this right because that's what we do so let's write it in a way that makes it just a little bit easier so I'm gonna go left out X comma left out y equals right dot X and come right down Y okay and then you see I don't need that extra and in there I don't have to make sure I get the that logic correct it's just this tuple on the left that I quickly create tuple on the right quickly create life is good and we can do the same thing of course with the not equal and then because people copy and paste code you know that at least in somewhere in your code base instead of the or there there's an and and it the logic is wrong and here I can just go left out X left out Y and it's just should not equal right that X comma right that Y cool I like it alright so now that's just a little bit smaller it's really clear what it means though that's just doing a couple little tricks with tuples which we'll have a few more as we keep going through some other core themes all right now I said we had this swap quartz thing I know what we're gonna do now that's now gonna be X comma y equals y comma X take that nasty interview person with your weird stupid programming questions because that's gonna work okay sitting with John skeet he showed me a version of this where he does the same kind of trick with the Fibonacci sequence and you get you know this current current neck's it's kind of cool so we start to do things like that because the way we defined this and we said we had to do this for the language is this going to evaluate all of the expressions on the right side to create that tuple and evaluate the expressions on the left side to find the variables those things store in and then do the assignments so this will work correctly and where we really needed that in practice other than for tricks like this is to be able to show things like you could have expressions on either side and things on the right side could change what happens on the left and we need to know exactly how that worked yes so that's cool so that's the first part that's just a few little trips tricks with tuples anytime you're looking at a couple maybe three sometimes four variables that you want to have travel together go ahead and put them in a tuple and use it knee of these tricks and again none of these really do anything different than what we saw before with the old code it is really a visual and a take a look at it and see if you like the way it looks for each for individual classes and individual struts that you're working with you know if you write this and you've got five or six things and it just looks bad or if you've got some really long variable names and it looks bad and don't but this is just something when it provides more clarity to what you're right go ahead and and do just that so now our next thing that I really want to talk about that we added and this was one that was added in the seven-point releases where we did a lot of work to make it more more better to write read-only structs and we've been saying to make value types immutable since c-sharp 1.0 that was all on all of you we really didn't provide a lot of support for that so what we have done now is let's say I said in my design you know this really should have been an immutable structu store these points I don't want them being modified once I've collected that data they should be never changing so now I can add the read-only modifier on the struct definition so if I wanted this to be immutable I would do that and now the compiler is you notice I've got red squiggles going out all over the place here because I didn't make it an immutable type in that any of the private member variables the compiler now tells me those must be read-only because they weren't this would not compile furthermore anything that tries to set any of those read-only variables well those can't be you know that's bad - you've said this was supposed to be a read-only struct now the impetus behind this was performance in certain areas in that now we want to be able to pass trucks by references we want to be able to do things like using span and reusing memory and if the compiler can enforce the fact that a struct doesn't change and cannot be mutated then that is a safer thing to do because we can pass this struct by reference we know it can't get modified and it's safe when it comes back or as if you pass something by reference and it could possibly be modified the compilers going to make a copy of it to make sure the codes correct so before I make this completely read-only this is where it gets to a lot of design decisions maybe I don't want the whole thing to be read-only so let's annotate what we can and say I know this method doesn't modify state so you know getting the export well that should be read-only so I can put the read-only modifier there to ensure that the get accessor does not modify anything inside this object okay that may look redundant but it really isn't because of property we know execute code so you could change state there again we'll do the same thing with the read-only on the on the Y and then here on distance right that shouldn't change state he said so we'll write the read-only modifier on that property quick thing to note if you have only a get accessor you cannot put the read-only modifier on the get accessor you have to put it on the property ok and if you notice as soon as I do that I'm now getting an error and another warning saying yeah you can't do this because you said this was read-only right so by saying it was read-only you're not allowed to modify the thing and now you really have a design decision to make as to what you wanted to do if you wanted to make this completely read only or if you wanted to still allow this lazy evaluation to go on now let's say every time I create a point in this particular application I'm always going to calculate the distance well then I would probably move that calculation up into the constructor and really make this read-only and cache that value let's say only 1 out of 1,000 points I'll calculate the distance then maybe I don't want to pay that cost and I would say ok I'm not going to make this read-only and then note that because this is going at the getting set properties it doesn't give me a warning here it's going to just say the same thing so it's here what we're trying to get at and what we want you to be able to do is anytime that you're looking at a struct only this read-only modifier cannot be added classes anytime you're creating a struct if your design was to make it an immutable struct add the read-only modifier on the struct if it was meant to be only some things are read-only then add it to those methods so I'm going to finish this up because I do want to show one or two other techniques that we've added is I am going to make this read-only and then we are going to deal with some of these these errors is now I'm going to use an implicit property here and now I'm just going to say well this is just just has a get access err and I am going to use the read-only property syntax when you do this whether it's in a read-only struct or not the compiler knows the code it generates and it automatically makes that property a read-only as the read-only modifier to it and il so that the CLI will know that that that X property is a read-only really read-only property and will do the same thing with Y and delete that I love deleting code and getting features and now that's of course going to be read-only as well I could add the read-only modifier here if I wanted to but it is redundant it doesn't add anything it's already there so now I'm going to have to change how I do the distance I'm going to remove the nullable attribute on it and here I'm just going to do the same trick I'm going to make this a get only accessor I'm going to get rid of all that do this and you know math dot square root x times X plus y times y all right and again you can see this gets just a little bit longer and this should be distance and these become capitals because I need to use the properties okay and now I have a truly read-only struct and now I have to just remove that because that was done for a bug somebody was just any data backwards so we needed that for a little bit but now I haven't truly read-only struct now the point of this trick in the point of what I want to say is this should enforce what your design is add these modifiers to enforce the design it will communicate to other developers what you meant someone comes in here later and wants to add a method and I call the read-only modifier was probably there for a reason maybe I shouldn't add something in the mutate state maybe I should do something to create a new point based on the existing data however I wanted to modify it so you communicate that design to others and you communicate it to the compiler the compiler will now help you enforce your design okay now a little bit of a sneak as to our next trick what we're going to do the other big feature we added in c-sharp eight is knowable reference types and once you get to dotnet core 3.1 more and more of the base class libraries have been annotated so that the api's now have the noble annotations so for instance I have no bubbles turned on here and if I have a method that looks like this I'm now getting a green squiggle here which is warning what that is telling me is as of dotnet core 3.1 the equals override has now been annotated with object could be null so it's an object question mark okay then I have to put that there okay this is one of the reasons why officially c-sharp eight is not supported on older frameworks while the nullable reference types feature for one is a big one that it's implemented completely compiler so the compiler would do the right thing the older libraries have not been annotated which causes two bad effects you will get warnings at times when you shouldn't and you won't get warnings at some of the times when you should so because of that it really doesn't help as much and it really would provide kind of a false sense of security if you added this into your code and expect everything to be good but you're not getting annotations from the libraries you use between now and net five and then net six we're going to continue to add more annotations into more of the dotnet libraries based on how many based on usage usage and download statistics that we have for which classes and which API is get use the most is it is quite a bit of work to annotate everything so between now and that net five nine and six as you start adopting c-sharp eight and nullable reference types with each new release you may start to see a few new warnings because more api's have been annotated but that should be pointing out potential errors in your code so we'd still want you to encourage you to start looking at it and start considering annotating your own code and turning this on where you can so next I'm going to get to as we talked about this and we start adding this here's something that we've learned over the course of time nullable reference makes the null reference exception is the single most reported exception on any dotnet app anywhere in the planet it is more than double any other exception type that we ever see in any telemetry that we see looking at open source projects on github checking for null is the single biggest expression and work that people do in code so let's do everything we can to make that more efficient so that you can add null checks without muddying the rest of your algorithms and I'm gonna admit I'm totally guilty of this because I do a lot of work in Docs and writing samples and we often don't check for null because the more null checks we add the harder it is to figure out the algorithm that we're trying to explain so instead of writing the code you would really have to write in production we trimmed some of these out and we're we want to change that habit ourselves as well and in doing this we're going to do some things to add things to the language to make null checks not take so many lines of code so let's look at our override of equals it's right now it's it's in at about ten lines of code there is really only one line of code here that has anything to do with the algorithm at all and that's the one that calls our operator equals that says this is value based equality check to see if all the properties are equal that's cool the rest of it is all related to the null check that's bad so let's try to shrink this out a little bit so let's do this and say alright so this if object is point other pt we're going to add some things with pattern matching so I'm just going to clear that here and then well now I'm just going to return this equals that I still need the bracket sorry don't want to get into that bug and now I have that okay so now I've I've shrunk that a little I'm feeling a little better it's a little bit more clear to see what you want okay now this is one that it depends on how you like the ternary operator or not but I can turn this into a single line expression and I can return is point other PT question mark boom yeah if not just return false okay and I would usually try to format that like this okay so now we have a very concise null check here if object is a type of a point if you've been a c-sharp program for a long time you knew that is for a long time only worked with reference types not with value types works with value types and now we can say it is and has an assignment in the same statement and then we're gonna just check equality if that test succeeded if not and if it was null it is not a point so the is operator only returns true if the object is not null whether it's a reference type or a value type in all there would always return false because it's not an object it's nothing okay so there we go slightly simplified way of doing null checks but to really do null checks you know remember I said I do either person classes or points so yeah now let's go over the person type we've got some reference properties and we have the same kind of thing here what I've got is I've got a person with first name and last name and we've got you know more than half of this code is the null track stuff okay thankfully though if you look closely you'll see three dots at the throw because this is something we we wanted to start encouraging and we say use a throw expression what does that do no okay so now if you look what this does I'm gonna add a carriage return here to make this little bit easier and as well just change this to the expression bodied members because you know the brackets are just taking up space for no apparent reason and I now have a set that says all right so first name equals value and then a double question mark just null coalescing operator and if value happens to be null then throw in your argument no exception okay so I like that I also like the way intellisense did that for me another little trick here that is my single biggest complaint about API consistency in the.net libraries is argument null exception the parameter name is first and the message is next in the argument exception they're reversed thank you very much so in all cases if you look at our Docs what we try to do is we try to use name parameters even though we often put them in the normal order and then in order to make sure refactoring works we use the name of operator for the param name just because then if I refactor this and I change the name of the argument that code will also be refactored so we can do the same thing here in this next one I've got the same kind of thing cool hit our light bulb and use the throw expression hey I can do it here and in my constructor - I'm now feeling really good about this yeah I can do the same one there and if you notice that I did all the null checks first and then the assignments and this refactoring knows enough to start to move those around and see those anywhere in a method so with most of the methods you'd write you do something like I'm going to test all the arguments first and then I'm going to go on and I'll do more things later the next one that I want to look at here is we added a method onto this person class to hyphenate last name for a partner so I could do a dot - 8b or depending on how the partners wanted to switch like a DB dot - a day and get a new last name that has the concatenation of those and you can see I have to check to see if partner is null and if it's not in all I'm gonna do this work to set last name and if it is now I'm gonna throw a null VAR argument exception now I wrote this in a slightly different way because I wanted to show something very important about the way the warnings get generated my mark said earlier in this project I have turned on turned on nullable reference types and I have all the warnings turned on so if you look at this argument this person argument it should be and it is declared to be a non knowable reference type okay so if I delete this null check and I just wanted to leave the null track okay I am not getting any warning any errors or warnings to say you might be dereferencing something that's null here this is not good because I declare it to be not nullable and then put the null Trax back and I'm going to point out that with your code when the compiler looks at anything that you've annotated with null reference types it pays attention to what you're doing and it does do a thorough static analysis of your code and what you've already written so this partner is a non nullable reference type but down here if I do a console dot write line and I could do partner dot last name okay now there it is I now have a warning under partner the green squiggles that is a nullable reference warning and if I hover over it it is going to say you know this you might be dereferencing null here okay even though the type was declared the argument was declared as a non nullable reference type because you added this null check the compiler goes I bet you did that for a reason crazy human programmer so because you did that for a reason and this line of code this console dot write line is not inside the block where you have checked it against null maybe you really is null here so I'm not going to trust the type system quite so much right there that's sort of the key to what not nullable reference types are they are annotations on variables it's not a new type and we're doing static analysis of the code to determine should we issue a warning here so as you're adding things when you have null reference checks those will affect the static analysis I am NOT encouraging you to remove null reference checks just so you know but I am pointing out what will happen with warnings however there is a neat trick that we can do to make these null reference checks simpler again I'm going to want to throw this no reference exception with if this is bad so I'm gonna move this up here and I don't want to do a no reference check with this if because this is just it's really old school but what I'm gonna want it to is I would like to use that same kind of a throw expression but if you look at that line of code where I do the return I'm just using person I don't really need to assign this to anything so I'm going to use a discard I'm gonna say discard equals partner or throw that in all reference exception argument null exception okay so the discard here is a special token that says if I don't already have a variable named underscore there this looks like a variable but the compiler can throw it away and in fact does not store anything to it so this is something we think is going to be idiomatic that we would like to encourage people to use more and more which is if all you're really trying to do is check to see whether an argument or a field or whatever is null assign that field to a a discard and when you have it and if the right hand side of that assignment is null add the question mark question mark throw and that's a null Chuck now the reason to do this you know we talk kind of about writing less code and I and I really think that that's less important than making your actual algorithm stand out more clearly the original version of this was about four lines long and more than half of the code in it was a null check and the throw we've now changed that in all check into a single assignment statement with an expression on it and then while this is a one-line method so it is reasonably simple whatever else you're doing now becomes the code that you would really look at right so what we're trying to do is make it so these these techniques that we have to use all the time just to ensure our code is correct and things don't crash and we don't get calls at weird hours takes up less of the code so that we can see that it's correct and we can really concentrate on the logic that we've written so for the last larger set of demos that I want to work with is dealing with pattern-matching which is something that we think is a really better way to write a lot of the algorithms that we have to write as we're working with data as working with data of different types and different properties and we're bringing data from different places possibly as JSON packets either from rest or graph QL and maybe looking at it and parsing it we need to create different object types and so on so the idea behind this is this is part of the system that does toll calculations so I'm going to start with the set of comments so imagine a large metropolitan city shouldn't be too hard right now and we want to discourage traffic at times that there's already an incredible amount of traffic so there's a toll system that does charges people to use the roads at peak times so the business people of complan have said all right so here's what we're gonna do on the weekends tolls are just its normal cost if you go overnight on a week night well that's when we want the lorries to do the deliveries and so on so we're gonna even lower it further so if it's the wee hours of the morning you only pay 75% of the normal toll day time so not rush hour but after morning rush room before afternoon rush well it's still pretty busy in the city so you pay one-and-a-half times if you're morning rush going into the city it's double evening rush going out of the city is also double okay so I made a few small I made an enum for morning rush daytime evening rush overnight is weekday okay this is a pattern matching switch expression okay so if you squint at it it kind of looks a little bit like a switch statement but these are all expressions so you know it's a lambda arrow and the right-hand side is always an expression it is not a set of statements or a block and there's no break we did switch the order and this is so that you can change them I can make the output of one switch feed into another switch expression because then that makes it a little bit more fluent so I'm gonna take what day of the week is it and I'm gonna switch on that value so that's an enum in the day time class they times struct and of course has Sunday Monday Tuesday Wednesday Thursday Friday Saturday and I'm gonna say if it's Saturday or Sunday well it's not a weekday anything else which is this discard character and a switch statement is match everything else well then it is a weekday so return return true this is a really good way to look at bits of data and make a determination about the values or the properties or the types of that data in this instance I'm making a determination based on the values of veneno so here when I did the time band well this talks about how worse we are still innovating and we are still going to add more we don't have a range pattern patterns have to be a particular value so if I take the hour I would need 24 rows here to match every different possible value 0 through 23 and that would look really ugly so here I am using some nested ifs one of the proposals that we're looking at right now is a range pattern that would say if our was between 0 & 6 or between 6 and 10 you know and we're looking at a way to add that which would simplify this guy so again going back to what I said at the very beginning this isn't necessarily go rewrite all your code use pattern matching look for places where it would make sense speaking of places where it would make sense so let's look at an imperative way to calculate that multiplier okay the first thing I'm going to do is I'm going to check to see if it's a weekday if it is a weekday I want to look if you're going into the city if you're going into the city then I want to look as morning rushes the daytime is evening rush oh it's something else that must be overnight okay this else matches inbound so now you're leaving the city so let's get the time of the tool I'm already off the page so I made the same call again I could probably refactor this but this is already really long and I wanted to remember what it was and again more is it morning what is it in the evening what is it overnight and so on and then we get back to this last else oh that's the weekend so the multiplier is one okay this code does not fit on one page it ends on line 95 it starts on line 46 so we have almost 50 lines of code and yes I know I'm following some coding standards that have braces we could remove the braces and we could shrink it but that leads to bugs so I'm not doing that that 50 line method is implementing those what six lines of business requirements including the comment that says this is exactly these are the business requirements so five different business requirements 50 lines of code it's that good business people are not going well about how much did you test this did you go through everything how do you are you sure this is something where we can really use pattern matching so we'll go ahead and implement this here from the pattern matching bed so I repeated the same business requirements here and now if you look at this once again I'm gonna use those tuples because now I've got three variables I'd like to make into one thing but I'm not going to define a class to hold whether or not it's a weekday which time band and is it whether or not you're going into or out of the city so I just made a tuple out of those three variables here on line 106 I've got his weekday time of toll get time bad time toll inbound then I've got the switch and now I can build a table with all the combinations of all those values copy and paste helped here and I didn't want you to watch me type all that but so there is this is what I need to fill in those lines don't take a picture yet a salt zero is this is broad okay so the first thing I can do is they look at my requirements all right so the weekend everything should be 1.0 great so I'm going to start here at the first false handle visual studio check if you press down alt you can select on a column so I'm going to just select this one column down there not quite there that's close enough and now just delete that one and then I can just write the one in there okay that's cool so now I fill that half the table life is good so now I've got okay so what did I say day time was I said day time was always going to be one or one and a half yes daytime is one and a half okay great so I need a 5 here and a 5 here morning rush if I'm going into the city is double if I'm going out it's the same overnight oh that was one 0.75 because you get a discount for the laurie's going in overnight and then evening rush I said that was going to be no wait I just messed this up didn't I these are so I was already in the wrong row that should be those were supposed to be the zeros that's still the weekend okay and then up here I've got evening rush going home is 2 going in is one day time I said that was gonna be 1.5 for both of them great morning rush going home or leaving the city is one going in is 2 okay great now I've got that that's that's not not that hard to really comprehend now right I've got 12 rows it's not bad okay but we can still simplify this a fair amount and again here I would really look at the code look at the options that you have look at how many rows you have how many different values you have to decide how far to go down this next set of refactoring I'm gonna do everything on the weekend back here with the falses well that's all all 1.0 I don't care what any other value is so I'm just gonna add a row here that does false don't care don't and that is gonna be one point oh okay now notice how I get the red squiggles on all of the lines below it this is will help you test if you're doing any of these you refactorings to see if you got it right by doing any of these refactorings with the warning or the errors and all of these says this which arm was already handled by something above it so there's no way to execute this code because the statement above it it's always gonna get handled okay that was exactly what I wanted so that's good now I can take these and I can delete them cool turns out if I want to be really fussy I can make this just another discard because well once I've handled all the true cases I don't care okay but we'll wait to do that one last now there's a couple other ones I can do here I look anything overnight is that 0.75 so whether it's true or false I can replace this with a discard okay and if I do that this one should turn red cool that was exactly what I wanted okay and then okay anything at the day time that's also one and a half I can do that cool and then this one should turn red there we go that's done okay that's nice cool okay I don't like the way this looks it's it's correct it's about as simple as I can get it but you know I'd like to kind of just let's just move this one up here and I'll leave the 1.0 is together okay and then I've got the ones that have thumb of that since it didn't add any squiggles well okay I'm okay I put him in an order that still works so now we took this thing that was 50 lines of code that was very imperative if then else if else if else if else that the other thing all of one-line branches and we said you know I can turn that into first it was 12 rows and now it's down to 6 rows and the real kicker that I want is not the amount of code that you're writing and how much of this there is but how clear is that versus how clear is that and it merely this is a little bit of a contrived example and you should play with this a little bit to figure out what works in your code and in your code bases but a lot of times when we're looking at properties looking at types or looking at values of data and we are making decisions on an algorithm this is an incredibly powerful tool to use and the more I've started to play with us and the more I've started to use it I find myself going I really want to reach for this tool very often okay so as we're getting close to the end I'm going to end with one really small quiz I don't want anyone to speak up with this but I'm gonna write a routine and this routine is gonna have a bug in it and when you spot the bug I want you to raise your hand so now this told people the business people have come back and said alright this system is working but we want to kind of reward people who are really regular and following things so we're gonna allow people to get a year-long subscription and pay in advance because of some cash up front we like that and then you know they can you know be like frequent drivers and do something better so I'm gonna make a public static method that's going to return a date time for the start and AJ time for the end and the method is going to be called generate subscription and what it's going to do well we need to figure out the start starts going to be today so far a start equals date time dot now dot date and you know it's going to expire one year from now so I'm going to do var and equals new date time I'm going to do start dot year plus one start got month because it's the same day right start that day okay all right I'm seeing tragically few hands come up so to make sure everybody can see the code well I'm going to leap over here this is a bug that's gonna show up one month from yesterday there are not enough hands about that that was a pretty good hit okay so everybody's got that what is this gonna do that's gonna be really bad anybody raise your hand really early good on the 29th of February 2020 this is going to crash because there is no 29th of February 2021 now the point of this little quiz is date time math is really really hard because this is probably the most obvious example and I did it here today because it is very timely so a better way to do this keeping this one fairly simple is start dot add years one okay because the dotnet Franco and I need to add the return start and the reason I did that out of that there's now the date time struct and any good day time library is going to handle all kinds of conditions whether it's a leap here whether it's yours it end in double zero that you'd think are leap years but aren't going on and going off summer time if you're doing math around hours and so on if you're doing really extensive stuff around culture john skeets not--it i'm open source library is incredibly powerful and does a lot more for a lot of reasonable things it's built in a date time but they did this in particular because i would actually look at your code a little bit and maybe do a quick search to see if you're just doing your own date time math and try and replace it with something that's probably tested okay so that's the code as we get close so the new habits the reason we went through all of these things and the reason I did some of this little light-hearted but focusing on a few different areas fun with tuples anytime you find yourself going I'm carrying a few bits of data and I really don't want to do all the work to make a struct think about using tuples there's also a proposal that we're working on for records which would be a very very short and better simpler syntax actually create a type if you needed it read-only members and read-only struct declare your intent when you're writing structs and value types and let the compiler enforce that and communicate it both of the compiler and to everyone who's going to read and maintain your code has a better chance of being correct over the long haul the examples I was showing where I was doing the question mark question mark initializations and other things like that the technique we refer to that as is natin all by initialization so the more often you can ensure that a field or an argument or a variable is initialized to something that does not null as soon as you declare it and create it at that point in text then you know that variable is never null and you can declare it as a non null reference type and you will the compiler will help you spot those errors remember that those are just in metadata so especially in public api's especially as you're in this process where you're probably migrating some code and some of it hasn't been annotated check for nulls anyway and especially in public api's as I said anything that we're doing we're annotating api's I can guarantee you we are not removing null chats patterns and data anytime you find yourself like switching on things and doing a lot of if-then-else some kind of logic by looking at a property looking at a type consider pattern matching it is a different way of thinking about a problem but it is a very very powerful way for certain classes of problem this is not to say stop using object-oriented stop using inheritance would never want to say that but if you looked at those algorithms I wrote I really didn't have an inheritance hierarchy to work with but have been really cumbersome one to make one that switch expression was actually much more powerful and a lot more clear in a smaller space for exactly what the code was doing that's what we're looking for and then the classic because I just really remind her date and time math and what I would make the recommendation here is do what you can to follow the good engineering software engineering practices that you're doing for your applications I'm sure all of you are building some kind of a culture of trying to write good software when that feels cumbersome do a little bit of research see if there's a better way to follow the really good practices without writing quite as much extra code specifically look for some new features and recommendations I used the light bulb today and there's also a screwdriver icon for other recommendations for purpose if you're using Visual Studio then you will get hints on some of the things that we think we've added features that you may not know about check that light bulb on the screwdriver and I meant this bit about talking about looking for the new research and do some research we love Stack Overflow and we love that it helps me every day too but very often now what we're finding because dotnet has been around for about twenty years is there are answers that have 15 years of uploads and they were great perfect answers for a long time and we've added features to make that yeah this will work but you know there's a better way to do it and the better way has maybe six months of upvotes so it's harder to find it and like Tessa was talking about in her opening keynote yesterday that's a positive feedback loop people keep seeing that first answer and using it even though there may be a better way so when I say do some research take a little bit more time including Stack Overflow we're trying very hard to stay up to date on Docs and check the recommendations from the IDE to try to find some slightly better things and use the things that we're adding to build some new build some new habits I could add ms / new c-sharp is where that's going to point to the latest c-sharp stuff I'm going to particularly call out two things that I put in here if you go into the sample browser which is Doc's that Microsoft comm slash samples and search for Explorer c-sharp you will see any of the things that we have that are going to help you explore some new things and new areas that one day I'll show another thing that we're doing is we have started adding a dotnet Docs what's new page so every month we will be publishing you know what's really big and new and as a bonus because we're all open source we are recognizing everybody who contributed to Doc's in the last month by their github IDs and if they have added their name to the github profile we will put it there but we don't dig any deeper than that and if you look at our tutorials the toll calculator is part of a much larger application on pattern matching that will take you up through a lot more techniques that you can use there thank you for your time I sure everybody's excited to get to the reception but I will be up here for any questions you can ask me questions now what I think we've got a couple minutes left and thank you very much for your time [Applause]
Info
Channel: NDC Conferences
Views: 211,569
Rating: undefined out of 5
Keywords: Bill Wagner, Languages, .NET, C# 8.0, .NET Core 3.0, NDC, London, 2020
Id: aUbXGs7YTGo
Channel Id: undefined
Length: 55min 45sec (3345 seconds)
Published: Mon Feb 17 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.