0

I tried to read up why mutable structs are evil, which was previously posted here.

Why are mutable structs “evil”?

But my post is more about a specific scenario.

Given following scenario

I want to have a small, fast to serialize "data class", to speed up my Save/Load Mechanism

I have a Player class which I can use inside the Unity Editor. This Player class has a member variable called "Stats" which is a struct.

public class Player : MonoBehaviour
{
    public PlayerStats Stats;
}

Below you can see the System.Serializable struct I am using as "data class"

[System.Serializable]
public struct PlayerStats
{
   public uint Speed;

   public void SetSpeed(uint speed)
   {
      this.Speed = Math.clamp(speed, Rules.MinSpeed, Rules.MaxSpeed);
   }
}

So later on to prevent the overhead i am experiencing from serializing a MonoBehaviour i use

JsonUtility.ToJson(player.Stats)

Now my question is, if I use SetSpeed anywhere in the code to modify the Value inside the struct

player.Stats.SetSpeed(3);

does this now lead to copies of the struct being made, because the value is being modified?

Any clarifications would be great.

  • For the performance of the serializer it makes no difference if you declare it as `public class PlayerStats { ... }` or `public struct PlayerStates{ ... }` – derHugo Oct 07 '20 at 08:43
  • On the saving (JSON generation) side it has no performance impact. But when loading it has to create either structs or classes and there i would say it starts to stack up. – EternalColor Oct 07 '20 at 18:23
  • 1
    Well this depends of course a lot on the amount but in general it doesn't really make a difference if creating a struct or class instance and deserialize the values into it. It is more a question if heap vs stack memory and whether you pass this to a lot of methods. Generally spoken a class is often the better option but it depends on the exact use case of course ;) it doesn't have to be a `MonoBehaviour` just use a simple class and you wouldn't have to ask this question at all ;) – derHugo Oct 07 '20 at 20:20
  • I followed the statistics/metrics given by this post https://medium.com/csharp-architects/whats-faster-in-c-a-struct-or-a-class-99e4761a7b76. It claims instantiating structs is 8.6 times faster than a class. Since im also saving all pathfinding nodes (custom pathfinding) there will be a lot of objects to save, up to 1 million. So this makes a difference for me – EternalColor Oct 07 '20 at 20:47

1 Answers1

1

No, changing the value of field in a struct does not cause a copy to be made. The copies are made when the structure is assigned to another variable. SetSpeed is a member function and has no struct parameter so won't cause a copy to be made.

For example, you call a method here:

JsonUtility.ToJson(playerDTO.Stats);

This will cause a copy of the structure to be made and assigned to the parameter inside the function, regardless of whether you later call SetSpeed. Any changes you make to playerDTO after this call won't change the local copy inside the ToJson function.

Perhaps in your case this isn't a concern (as in many cases). In other cases people could use a struct when actually they want to pass something by reference, in which case they would not get the behaviour they desire.

Just as an example for better understanding

// obviously creates a new Stats instance
player.Stats = new Stats();

// only changes the value inside the instance - no copy
player.Stats.Speed = 3;

// A new copy
var states = player.Stats;

// Creates and passes a COPY to the method 
JsonUtility.ToJson(player.Stats)

// again no copy
player.Stats.SetSpeed(3);

And just for providing one example for a well known struct type ;)

// stores a COPY 
var position = transform.position;

// only changes a value - no copy
position.x = 4;

// normalizes the instance itself - no copy
position.Normalize();

// Assigns a COPY
transform.position = position;
derHugo
  • 83,094
  • 9
  • 75
  • 115
ekke
  • 1,280
  • 7
  • 13
  • 1
    I just felt so free to add some code examples for better understanding, hope that is ok with you :) – derHugo Oct 07 '20 at 08:21