C# 7 Series, Part 3: Default Literals


C#’s default keyword has two kinds of usages: one is to label the fallback branch of the switch…case structure (for any path that does not fall into the case conditions); another is to represent the “default” value of a type. I will discuss this usage in this blog.

The default value of a type is either:

  • null, if the type is a reference type, or
  • an instance of the type constructed with the parameterless constructor, if the type is a value type.

The following screenshot is a quick example.

image

However, you can not have a default expression for any open type (Note: An open type is a type that has unbound type arguments; a type has all bound type arguments is called closed type), for example:

image

Now, if we want to use default value for a generic type in a method, we have to write code like this:

public static void Method(ImmutableArray<int> array) { }
 
public static void Main(string[] args)
{     
Method(default(ImmutableArray<int>)); }

Do you see a redundant here? the compiler should know the exact type needed for the Method() for the first parameter. A default literal without the type specification should be sufficient enough.

Default Literals

C# 7.1 allows the default expressions. If compile with the C# language version 7.1, or latest, you can simplify the code as the following:

public static void Method(ImmutableArray<int> array) { }
public static void Main(string[] args)
{
Method(default);
}

Now you get a clean code!

Similarly, you can have default literals for all the place that default(…) can appear:

public static void Main(string[] args = default)    // Default value for the optional parameter        {
int i = default;        // Default value (0) for type System.Int32 
    string s = default;     // Default value (null) for type System.String 
    Method(default);        // Calling a method with default value for an argument 
    T t = default;          // Default value for a type parameter 
    return default;         // Default return value for a method that does not return void 
}

You can have default literals in a condition test:

int x = 2; 
if (x == default) { }       // Test if x is default value (0) of the type System.Int32 
if (x is default) { }       // Same as above

More interestingly, you can use default literals in switch…case. Oh, cool! but… wait, how about the label ‘case default’? Here is what I get from the IDE:

image

And if you apply the fix, it will be:

int x = 2; 
switch (x)
{
    case (default): break;
    default: break;
}

This looks confusing, but at least we get live analytics about this, Thanks Roslyn!

The last thing I want to call out is there are cases that cannot apply default literals, for example:

// Error: 'as' must have reference type 
default as int;
// OK. But the left hand expression is always null. if (default as string == string.Empty) { } // Error. Cannot apply operator 'is' to type 'default'. if (default is string) { }

Conclusion

Default literals in C# 7.1 avoids redundant typing where the default value is known to compiler. This is a syntactical improvement and nothing changed for the CLR, The new code is 100% compatible with the code built by earlier versions of the C# compiler.

Comments (9)

  1. Veruthas says:

    How do you differentiate between ‘case default’ and ‘default’ in goto statements? Would it be ‘goto (default)’ vs ‘goto default’?

    1. Veruthas says:

      Ah it would be ‘goto case default’, doh! Sorry Mark.

    2. Yorgi says:

      If you need use “goto” statement in your code that means something goes terribly wrong

      1. William Wong says:

        I would say it really depend on what problem needs to solve by “goto”. There are cases such as switch-case that use ‘fall through’ requires “goto”, e.g.
        switch (i)
        {
        case 0: // direct fall-through without using “goto”, as no body inside this “case”.
        case 1:
        // something done here
        goto case 2; // we need “goto” here as there IS body.
        case 2:
        // do things
        break;
        default:
        break;
        }

        Of course you are saying other kinds of “goto” (from traditional C/C++ thought), unfortunately, I also saw some code from .NET Core that really requires this kind of goto in order to write less similar-to-same code.

  2. semkoa says:

    What if you have multiple parameters in a method? In my opinion the default keyword is much less readable than having the type as parameter. For example:
    Method(default(ImmutableArray), default(ImmutableArray), default(ImmutableArray));
    vs
    Method(default, default, default); // hard to remember which one is which?

    1. CookieMonster says:

      In my opinion if you want to allow for this kind situation is better to introduce optional parameters:
      Method(ImmutableArray a = default, ImmutableArray b = default, ImmutableArray c = default)

    2. Julien Couvreur says:

      This is true for any literal. I am working on a c# 7.2 feature to address this: an improvement to named arguments.
      You will be able to write `M(ignoreEmpty: true, accumulator, cancellation: default);`.
      It is more informative to specify the name of the argument, than the type in `default`.

  3. Alexandre Trepanier says:

    why not a three letter word like “def” instead of “default” .. you don’t use def anywhere in c#

    seriously “default” will creap in the code.. =) , even just underscore “_” would have been better than both..

    return _ ;
    string[] args = _ ;

    1. Many people, me included, will always choose readability over length of the code. There’s no way I could choose cryptic special characters over plain English words.

Skip to main content