- Home /
Property vs Field. Which is faster?
Hello!
I've seen some Unity Optimization tips that is faster to store the reference of a component in a variable rather than using the property of it. For example, transform. I always create a private field in my classes called m_transform containing a reference to the transform.
The thing is, I am using the singleton pattern all over the place for important Classes such as GameManager, SceneManager, PlayerController, CameraController etc.
public static GameManager instance {
get ;
private set;
}
I was wondering if calling this property inside the Update function is slower than using a field to store the reference to the GameManager.
switch (GameManager.instance.currentState)
{
case GameManager.GameState.InGame:
// code here
break;
}
What do you guys think?
Answer by Bunny83 · Jul 04, 2017 at 04:11 AM
The problem is not that a property is slower than a field. A property is actually a method (or a pair of methods). What those methods do and how expensive they are depends entirely on that method.
It's usually just a waste of time to cache the Transform component manually as Unity already cache it internally. All other short-cut-properties do no longer exist (.renderer, .rigidbody, .collider, .light, ....)
You declared a so called "auto-property" which is the same as doing:
private static GameManager m_instance;
public static GameManager instance
{
get { return m_instance;}
private set { m_instance = value; }
}
This property is just a wrapper for a field. However in theory a property could do anything within it's methods:
public int MyProp
{
get
{
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.transform.position = Random.insideUnitSphere * 20;
go.transform.rotation = Random.rotationUniform;
return 42;
}
set
{
Camera.main.transform.rotation = Quaternion.Euler(0,value,0);
}
}
This property would create a new cube at a random position every time you read the property.
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
int val = MyProp * 2; // <<--- this line would create a new cube
Debug.Log("Val is " + val); // <<-- this will always print "Val is 84"
}
MyProp = Time.time; // <<-- this will actually set the main camera rotation.
}
Note that this is a perfect counter-example. Never do something like that. It was just an example to show that a property could perform any heavy task behind it's "variable-like" usage.
That's why a singleton is usually implemented like this:
private static GameManager m_Instance = null;
public static GameManager Instance
{
get
{
if (m_Instance == null)
{
m_Instance = FindObjectOfType<GameManager>();
if (m_Instance == null)
throw new System.Exception("No GameManager found!");
DontDestroyOnLoad(m_Instance);
}
return m_Instance;
}
}
This is a self-initializing singleton accessor. So the first time you "read" the property m_Instance might still be "null" so we use FineObjectOfType to find the instance in the scene and initialize the field. If there is no GameManager in the scene it will throw an exception.
If the GameManager was found the first time, any further access of that property will directly return the cached instance. It also takes care of marking the instance with DontDestroyOnLoad so it's persistant across scenes.
In general the overhead of a property getter is in most cases too small to even be measured. Also simple getters will most likely be inlined either by the compiler or by the jit compiler.
A practice of $$anonymous$$e is to use properties to make sure I initialize a collection, such as a List or Array.
public class SomeClass : SomeBaseClass {
List<objectType> m_objectTypes;
public List<objectType> ObjectTypes
{
get
{
if (m_objectTypes == null)
m_objectTypes = new List<objectType>();
return m_objectTypes;
}
}
}
While it is possible to use a property like this for lazy-initialization, it would be easier to just use a field initializer. If you worry about someone overwriting the value you can mark it as readonly
public class SomeClass : SomeBaseClass
{
public readonly List<objectType> ObjectTypes = new List<objectType>();
}
$$anonymous$$eep in $$anonymous$$d that readonly does only apply to the variable itself, not the List it contains. So the list can still be used as usual. It just can't be "replaced". Though your property approach does pretty much the same. Once the value is initialized it can't be replaced.
Heei! Thank you for all of the explanation! And examples. I always used something like the example you provided:
public static Game$$anonymous$$anager instance
{
get
{
if (!m_instance )
{
m_instance = FindObjectOfType<Game$$anonymous$$anager>();
if (!m_instance)
Debug.LogError("No Game$$anonymous$$anager found in the scene!");
}
return m_instance;
}
private set { m_instance = value; }
}
private static Game$$anonymous$$anager m_instance;
(for a single scene)
Your answer
Follow this Question
Related Questions
Is it costly to get a singleton instance each frame ? 1 Answer
DontDestroyOnLoad 1 Answer
Singleton vs AddComponent 3 Answers
Sharing materials in unity 1 Answer
Is it possible to not allow unity optimise my code? 1 Answer