9

I'm using VisualStudio 2017 on a project that targets .NET Framework 4.6.1.

Playing with Task, CancellationToken and a local method, I came to this code:

class Program
{
    static void Main(string[] args)
    {
        CancellationToken o;
        Console.WriteLine(o);
    }
}

Which compiles. Now if you change the type of o to an int or a string it won't compile, giving the error:

Local variable 'o' might not be initialized before accessing.

I tried to decompile CancellationToken and copied the code in a struct named MyCancellationToken. That won't compile either.

The only case I managed to make compile is an empty struct or a struct containing a CancellationToken.

struct EmptyStruct
{
}

struct MagicStruct
{
    public CancellationToken a;
}

class Program
{
    static void Main(string[] args)
    {
        EmptyStruct a;
        MagicStruct b;
        Console.WriteLine(a);
        Console.WriteLine(b);
    }
}
  • Why doesn't CancellationToken need initialisation?
  • What are the other types that don't need initialisation?

Fun fact: if you mix this with a local function you can write this:

class Program
{
    static void Main(string[] args)
    {
        Work();

        CancellationToken o;

        void Work() => Console.WriteLine(o);
    }
}

Which compiles.

Boann
  • 48,794
  • 16
  • 117
  • 146
Orace
  • 7,822
  • 30
  • 45
  • then i am wrong in that case – Pranay Rana Apr 11 '18 at 09:39
  • 1
    @Fildor: I think the point is that it is being comprehensive. It doesn't work if its a struct. It doesn't work if its a class. The two aren't being equated to each other, they are being used as examples that should cover all the types of object that exist (structs and classes). – Chris Apr 11 '18 at 09:40
  • There was a question about this on SO recently. It's an intentional compiler deviation from the spec (the spec says you should get an error) when a struct in another assembly only contains private fields of reference type. Let me see if I can find that other question. –  Apr 11 '18 at 09:40
  • See https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-structs#example-2 Unlike classes , structs can be instantiated without "new" ... Quote: _"Description This example demonstrates **a feature that is unique to structs**. It creates a CoOrds object without using the new operator. If you replace the word struct with the word class, the program will not compile. "_ – Fildor Apr 11 '18 at 09:42
  • @Chris If you put it that way, it makes sense, yes. – Fildor Apr 11 '18 at 09:42
  • @hvd, indeed it works – Orace Apr 11 '18 at 09:44
  • That other question was about [`Span`](https://stackoverflow.com/q/49653151). Orace, is it okay to close this question as a dupe of that, or are you interested in some things not answered by that? –  Apr 11 '18 at 09:45
  • 3
    @Fildor Because "Why doesn't `CancellationToken` need initialization?" and "Why doesn't `Span` need initialization?" are fundamentally the same question and have exactly the same answer. –  Apr 11 '18 at 09:48
  • 2
    @Fildor It's the exact same glitch at play here. `CancellationToken` is not an empty struct. It has a private field of reference type. –  Apr 11 '18 at 09:50
  • 1
    @hvd. Ahhh, yes. I read it again, I see it now. – Fildor Apr 11 '18 at 09:51
  • Answer is here https://stackoverflow.com/questions/4945474/why-in-c-sharp-we-need-to-initialize-primitive-type-variable That seems is c# compiler things. But I can't find any information how struct is being assigned to autoinitialize category depending on its fields – Evgeny Gorbovoy Apr 11 '18 at 10:00
  • C# during compilation checks the inner structure of a struct and if it does not have primitive fields it makes autoinitializing for this. Kinda useful, but I can't find official information( – Evgeny Gorbovoy Apr 11 '18 at 10:04
  • @EugeneGorbovoy Actually it's the reciprocal question – Orace Apr 11 '18 at 10:04
  • Thanks for confirming, closed. –  Apr 11 '18 at 10:05
  • Wait, so actually what's going on? I found only a bug about this: https://github.com/dotnet/roslyn/pull/25886/files But actually where is any info when I can use automatic initialization and when not? – Evgeny Gorbovoy Apr 11 '18 at 10:07
  • @EugeneGorbovoy I think you're confusing class fields with struct fields. Class fields are auto-initialised to `default` (for any type, value type or reference type alike). Struct fields are not supposed to be auto-initialised at all. –  Apr 11 '18 at 10:11
  • @hvd I'm not talking about fields initialization, but about variable initilization. I'm saying - in case of CancellationToken o; - compiler makes initialization for you (in case of empty struct too), it can be seen after disassembling. But why does it do it? – Evgeny Gorbovoy Apr 11 '18 at 10:13
  • @EugeneGorbovoy Empty structs are treated just like all other structs. They're considered initialised as soon as all fields have been assigned a value. It's just that for empty structs, that's immediately the case even without any assignment. That's different from what's happening with `CancellationToken`. –  Apr 11 '18 at 10:16
  • So why CancellationToken or span are considered initialized, and actually where is documentation about this? – Evgeny Gorbovoy Apr 11 '18 at 10:22
  • 1
    @EugeneGorbovoy [Specification](https://github.com/dotnet/csharplang/blob/master/spec/variables.md#definite-assignment): A *struct_type* variable is considered definitely assigned if each of its instance variables is considered definitely assigned. – user4003407 Apr 11 '18 at 10:33

0 Answers0