Is CompareTag better than gameObject.tag performance wise?

Hello,
Someone told me that this:

Note: code below is not C# but, now obsolete, JS-like Unity Script.
function OnTriggerEnter (other : Collider) {
	var deathMenu = GetComponent("");
	if (other.CompareTag("Lava")) {
		
	}
}

Is better than this:

function OnTriggerEnter (other : Collider) {
	var deathMenu = GetComponent("");
	if (other.tag == "Lava") {
		
	}
}

Is that true? Thanks.

Where are you from? :D

You may want to consider accepting the answer that explains that CompareTag does not cause memory allocations - it's a very important difference that was missed in the previously accepted answer.

7 Answers

7

CompareTag compiles to fewer CIL instructions than the direct comparison, for sure: it probably results in a single call to the CompareTag internal function, while the other alternative will need a call to the tag getter function (to get the tag string) and another call to the string comparison function, all of this in CIL (the interpreted language used in .NET applications). Since the tag string must be returned by the getter function, space must be allocated, what takes extra time.

Anyway, the difference probably is very small, but may become significant if a lot of CompareTags is used in Update or OnCollision/TriggerStay, and/or the target machine is a mobile device.

So, why would someone ever use '.tag' other than to use the result in a switch statement?

I use it for assigning tags in editor for example.

You might use obj1.CompareTag(obj2.tag) (obviously not appropriate for checking for equality, but useful for type matching).

Do you have any insight on the inner workings of CompareTag? Isn't it possible to have the == operator overloaded for this case?

Hi, I'm new to Unity, using Unity 5, I followed Unity Tutorials... What's the difference between other.gameObject.CompareTag(" ") and other.CompareTag(" ")? Same apply with other.gameObject.tag == " " and other.tag == " "? Are they the same?

The key difference between tag and compareTag is that compareTag does not result in a heap allocation. In Unity, retrieving strings from game Objects will create a duplicate of the string, which will need to be garbage collected.

The source I found reports a ~27% increase in performance of compareTag(aString) vs. using gameObject.tag == "aString";

Source:
Unity 5 Game Optimization by Chris Dickinson

One other big item no one else mentioned.

CompareTag check to see if the tag actually exists and Unity will throw an error if it doesn’t. Just comparing string won’t do that.

What i realised is that, if you have a parent object with the tag "A" and a child object with tag "B":
you want to run a function when the tag is "B".
if you use if(other.gameObject.tag =="B"), it is not going to return true, because gameobject.tag returns the parent object’s tag. so it’ll return "A" and its false. its not going to run.
But, compareTag("B") just returns whatever you’re colliding with. ( even if it has a parent with a different tag.) so it’ll return true.

so compareTag is more like doing this → other.collider.tag.
other.collider.tag returns the Collider’s tag, so, in this case it returns "B". as well.

just realised that, so, wanted to share.

//
// Summary:
//     The tag of this game object.
public string tag { get; set; }

//
// Summary:
//     Is this game object tagged with the tag?
//
// Parameters:
//   tag:
//     The tag to compare.
[FreeFunction(Name = "GameObjectBindings::CompareTag", HasExplicitThis = true)]
public bool CompareTag(string tag);

Note:

In most of the unity talks I noticed compare tag with the collider. And about the tag, I used it whenever I want to confirm the tag of the specific gameObject within the script.

‘gameObject.tag == “”’ is faster. Here is the code I used to determine that:

using UnityEngine;
using System.Diagnostics;

public class CompareTagBenchmark : MonoBehaviour
{
	public int runCnt = 100;
	int runNum;
	float dur;
	float dur2;

	void OnEnable ()
	{
		runNum = 0;
		dur = 0;
		dur2 = 0;
	}

	void Update ()
	{
		Stopwatch stopwatch = Stopwatch.StartNew();
		if (gameObject.CompareTag("Untagged"))
		{
		}
		stopwatch.Stop();
		dur += stopwatch.ElapsedTicks;
		Stopwatch stopwatch2 = Stopwatch.StartNew();
		if (gameObject.tag == "Untagged")
		{
		}
		stopwatch2.Stop();
		dur2 += stopwatch2.ElapsedTicks;
		runNum ++;
		if (runNum >= runCnt)
		{
			print(dur / runNum + "\n" + dur2 / runNum);
			enabled = false;
		}
	}
}

This is a pretty flawed benchmark. Also this thread has already been answered over a decade ago. There's no need to necro post with no new information.

Operator comparison will create one more string object, which is to be deleted very soon and that makes it generation 0 on the heap. Microsoft claims garbage collector is blazingly fast on gen0 for .NET Framework, but I don’t know the situation for Mono.

As a veteran software developer I would recommend ignoring such micro optimizations unless it is called more than a hundred times per frame. I think such optimizations are in the category of compiler optimizations.

Now time for shameless marketing :slight_smile: Code Enchanter automatically converts all of your tag operator comparisons to method comparisons from your source code.

For example myObject.tag == “myTag” to myObject.CompareTag(“myTag”)

It has some other performance tricks as well, it’s available on Code Enchanter | Utilities Tools | Unity Asset Store