1

I know it's kind of a basic question, but it doesn't seem there is a clear answere around. When you declare an array as a class field, variable size-determined at the run time is not allowed,

public class MyClass : MonoBehaviour{

    int size = 6;
    float[] f = new float[size]; //not allowed

    // Start is called before the first frame update
    void Start()
    {
      //some code
    }
}

while declaring it the same way but as a local variable inside a function e.g. Start is perfectly fine:

public class MyClass : MonoBehaviour{

    void Start()
    {
        int size = 6;
        float[] f = new float[size];

        //some code
    }
}

Is this related to the scope of the variables? Or with the where the memory allocation takes place stack, heap etc? Thank you in advance

mich.m
  • 13
  • 4
  • 1
    I believe when you are declaring as member variable then a compile time error is raised stating `A field initializer cannot reference the non-static field, method, or property`. The error itself states the cause of compilation error. Now, if you want to declare as field then defined the size as `const` so that size value is available at compile time only... Chnage `int size = 6` to `const int size = 6` – user1672994 Jun 04 '21 at 10:14
  • 1
    Of course you can vary the size of an array field *if you initialize it in the constructor* rather than trying to initialize it inline with the field declaration itself. You need to distinguish between declaration and initialization. – Damien_The_Unbeliever Jun 04 '21 at 10:21
  • Thanks for the answer. I know the workarounds (use List instead of array, declare it as a const, etc.). What I was looking for was an insight about the reasoning, why C# would allow it inside "Start" function. Moreover, according to another post, it seems that intializing inline and initializing inside a constructor doesn't seem to make a difference with respect to what is allowed and what is not https://stackoverflow.com/questions/24551/initialize-class-fields-in-constructor-or-at-declaration – mich.m Jun 04 '21 at 10:32
  • Class fields are initialized in a `static` context because it happens **before** the constructor is called so `this` doesn't exist yet and therefore you can't reference anything that is instance based .. only other `static` stuff – derHugo Jun 04 '21 at 20:26

2 Answers2

2

There is clear answer to this and you can find it in specification:

A variable initializer for an instance field cannot reference the instance being created. Thus, it is a compile-time error to reference this in a variable initializer, as it is a compile-time error for a variable initializer to reference any instance member through a simple_name. In the example:

class A
{
    int x = 1;
    int y = x + 1;        // Error, reference to instance member of this
}

the variable initializer for y results in a compile-time error because it references a member of the instance being created.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
1

As per the docs "Unlike the classes in the System.Collections namespaces, Array has a fixed capacity. To increase the capacity, you must create a new Array object with the required capacity, copy the elements from the old Array object to the new one, and delete the old Array."

Compile error CS0236. "Instance fields cannot be used to initialize other instance fields outside a method" + Instance field initialization spec explain the issue.

For the same reason you are not able to do this:

    int int1 = 3;
    int int2 = int1;
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
rustyBucketBay
  • 4,320
  • 3
  • 17
  • 47
  • _"That is why you cannot set the size of the array with a variable, an a compilation error is thrown."_ but the second snippet sets the array size with variable (and works completely fine) – Guru Stron Jun 04 '21 at 10:31
  • Thanks for the answer. I know that arrays are designed be default to be static DS and it makes sense not to allow a variable as the size of the array -that's the purpose of List class-, but then why is it allowed inside the "Start" function? My question is to have a better understanding of the memory model of C# and Unity rather than simply find a solution to just make it work. – mich.m Jun 04 '21 at 10:37
  • thats right, I updated the answer. Its a c# thing, not unity's – rustyBucketBay Jun 04 '21 at 10:46
  • _"On the other hand, there is not warranteed order of initialization of variables so the compiler can rearrange these, so at runtime there is no guarantee size will be initialized before float[] f, so you would be oxposed to have NullReferenceException"_ This is VERY wrong. `int` can't get you `NullReferenceException`, and *"The variable initializers are executed in the textual order in which they appear in the class declaration"* as stated in language [spec](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#instance-field-initialization). – Guru Stron Jun 04 '21 at 11:19
  • So the order of initialization is guaranteed. – Guru Stron Jun 04 '21 at 11:19
  • @GuruStron is correct, his should be the accepted answer – rustyBucketBay Jun 04 '21 at 11:27
  • I updated the ansewr, @GuruStron brought point from the [spec](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#instance-field-initialization) plus the compilation error produced [CS0236](https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0236) explain the OPs question – rustyBucketBay Jun 04 '21 at 11:31