Home > Software design >  Why can't I change value without first assigning a variable?
Why can't I change value without first assigning a variable?

Time:10-30

Hi I stumbled upon something strange, I wanted to stop the emission of particle system as follows:

laser.GetComponent<ParticleSystem>().emission.enabled = false;

But I get error CS1612 (cannot modify the return value cause it is not a variable)

But

var emissionModule = laser.GetComponent<ParticleSystem>().emission;
emissionModule.enabled = false;

Works, now I searched about this issue but everyone says you can't do it because the return value is returned by value and not by reference, but this can't be true because the code above does indeed change the emission module to false in game, it didn't change a local copy in my code it actually changed it on the reference, so my question is why creating a variable first does anything different then just changing it on the same line? it would have worked in JS/Python

If I had to do something like

var emissionModule = laser.GetComponent<ParticleSystem>().emission;
emissionModule.enabled = false;
laser.GetComponent<ParticleSystem>().emission = emissionModule

I would have understand this issue better, but I don't need to do it like here, I don't need to assign it back again somewhy, it works fine as I showed in the 2nd example so it doesn't make sense, emissionModule seems to be a reference and not a value copy



TL;DR version:
Here is a full example of the code:

void changeLasers(bool isActive) {
    foreach (GameObject laser in lasers) {
        var emissionModule = laser.GetComponent<ParticleSystem>().emission;
        emissionModule.enabled = isActive;
    }
}

Which is weird, it works but I didn't need to assign it back again so why couldn't I do it in 1 line? seems weird that c# forces me to use another variable here. This gives the CS1612 error:

void changeLasers(bool isActive) {
    foreach (GameObject laser in lasers) {
        laser.GetComponent<ParticleSystem>().emission.enabled = isActive;
    }
}

CodePudding user response:

emissionModule seems to be a reference and not a value copy

Well, it is not ;)

EmissionModule is a struct and therefore the ParticleSystem.emission property returns a copy by value!

Since Unity is actually mainly a C engine and the c# is just a layer on top of it most of the components properties are actually just wrappers for getters and setters into the underlying C part where they are actually implemented. (See source code)

=> Most of the properties in Unity behave exactly like that and you always need to use the getter, store them, modify them and assign them back again.

In this case it is very possible that internally that struct still aslso holds a reference to the system which allows the enabled property to directly affect the underlying system.

Still since c# is how it is you can not directly modify the value of the returned struct.

CodePudding user response:

derHugo's answers the c# issue here (we indeed get a struct by value),
I want to chime in about why we don't need to re-assign the structure back:


It wouldn't have worked normally, this is black magic done by the Unity engine behind the scenes (basically applies your struct changes without you needing to re-assign the struct back).

More on this subject here:
https://forum.unity.com/threads/is-particlesystem-emissionmodule-a-struct-and-how-should-we-use-it.821988/
And a bit more detailed:
https://blog.unity.com/technology/particle-system-modules-faq

  • Related