Less is more in C# 10

Sometimes you don't know you want something until you get it.

File Scoped Namespaces

File Scoped Namespaces is one of those things. Why hell do we start off every. single. file. with wrapping everything in a namespace and curly brackets.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyApplication.Application.AwesomeFunctionality
{
    public class NicenessDto
    {
        public string NiceQuote {get; set;}

        public NicenessDto(string niceQuote)
        {
            NiceQuote = niceQuote;
        }
    }
}

Up until C# 10, the above example is the required syntax in C# to put a class in a namespace, and import the things you needs access to with the using directives.

The reason for this is that you can actually have several namespaces in your files (something you probably already knew about, but never actually uses). The same goes for all the usings. You can control which libraries you can access in your file, many of which are repeated in almost all of your files.

A big ask from the community and those trying to teach C# and .NET to new developers is a simplification of the way we structure files and reduces the amount of duplicated (Boiler Plate) code.

As a result of this Mads Torgersen and the C# team have changed their philosophy regarding what changes are made to the language.

They don't want to have backwards incompatibility, but they can also see that some things are done the same way by 99%+ of all developers.

Analyzing all the C# code on GitHub, they found out that almost all .cs-files have exactly one namespace.
This means that most of the C# code in existence is indented by exactly one tab (or more likely, four spaces) for no other reason that there is the possibility that you might want more than one namespace in your file - but you probably won't

The change is that you can now just do this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyApplication.Application.AwesomeFunctionality;

public class NicenessDto
{
    public string NiceQuote {get; set;}

    public NicenessDto(string niceQuote)
    {
        NiceQuote = niceQuote;
    }
}

And it remove a full level of nesting of your entire file. Imagine how much empty space can be saved if this is done for all the files that exist with just one namespace! It has to be in billions of spaces and tabs that doesn't need to take up space in the cloud and on you monitor.

Also, how many times have you had to look at linebreaks or horizontally scroll when code reviewing in a browser window. Now you might have to do that a little less often!

If you are mad at this feature and think it unnessesary, then fine - just do what you have always done. But it removes a little bit of empty space and mental overhead, which is objectively a good thing. Even though we are all used to the old way have to learn some new habits.

Global Usings

The same thing applies to our usings. So many things are imported into almost all the files in our projects, and now we finally have the abilty to clean out a little bit of all the repitition.

If you, for example use System in almost all of your files, you can now add it everywhere using the global keyword once, anywhere in your project.

global using System;

This means that you now only need to have it in one of your files, and then not waste lines at the top of your files ever again.

The best practice for global usings, is to keep them in one file, used just for that, this allows you to get a better overview of what you are actually using in your project.

You can still have regular using directives in your files, and they will override the global usings.

This all means file from the beginning of this post would look like this instead:

namespace MyApplication.Application.AwesomeFunctionality;

public class NicenessDto
{
    public string NiceQuote {get; set;}

    public NicenessDto(string niceQuote)
    {
        NiceQuote = niceQuote;
    }
}

No extra indentation, no noise in the beginning of the file. Just a declared namespace and the actual code of the class.

The compiler makes sure that no bits are included when compiling your files, just like it already did if you put a using directive in a file and didn't use it - but now you don't need to clean up your usings in the all the files when you refactor your code. Aaaaaaah!

Conclusion

As developers we spend most of our time reading code and for this reason I really think the most important thing the language designers can do to make developers more productive, is to improve readability and remove as much noise from the language as possible. The steps in isolation doesn't always seem to be huge changes, but when you multiply it up to the scale of whole systems they actually do have a meaningful impacts.

Kudos to Mads and the team for this one!

Mikkel Secher

Mikkel Secher