When an object is converted to a String, it is first checked for a toString() method. But there are subtleties to this that you may not have considered.

The behind-the-scenes call to your class’ toString() method can be very convenient:

class Vector3
{
	public var x:Number;
	public var y:Number;
	public var z:Number;
	public function toString(): String
	{
		return "Vector3 [x=" + this.x + ", y=" + this.y + ", z=" + this.z + "]";
	}
}
 
var vec:Vector3 = new Vector3();
vec.x = 2;
vec.y = 4;
vec.z = 6;
trace(vec); // Vector3 [x=2, y=4, z=6]

Thus you are spared the ugly default [object Vector3] and instead have a useful output for, say, a debug log. Now let’s look at some less straightforward usage:

public function toString(d:uint): String
{
	return "Vector3 [x=" + this.x.toFixed(d)
		+ ", y=" + this.y.toFixed(d)
		+ ", z=" + this.z.toFixed(d)
		+ "]";
}

Here we have changed the signature of the function to add a parameter to specify the number of fractional digits in each component of the vector. This is useful and will not yield a compiler error or warning. So what happens when we go to use it?

trace(vec.toString(3)); // Vector3 [x=2.000, y=4.000, z=6.000]
trace(vec); // ArgumentError: Error #1063

In the latter case the player passes no arguments and an error is thrown. You can still use toString() in an unconventional way, but it’s fraught with peril! Luckily, there’s a good workaround using default parameters:

public function toString(d:uint=3): String
{
	return "Vector3 [x=" + this.x.toFixed(d)
		+ ", y=" + this.y.toFixed(d)
		+ ", z=" + this.z.toFixed(d)
		+ "]";
}
trace(vec.toString(5)); // Vector3 [x=2.00000, y=4.00000, z=6.00000]
trace(vec); // Vector3 [x=2.000, y=4.000, z=6.000]

How about if you made it a static function?

public static function toString(): String
{
	return "A class representing a 3D mathematical vector";
}
 
trace(vec); // [object Vector3]
trace(Vector3); // A class representing a 3D mathematical vector

As you see, toString() even works with Class objects by calling any static toString() present! I found this out when it recently bit me in come code similar to this:

class ObjectUtils
{
	// An easy way to print all of an object's properties, delimited
	// by anything (eg. a comma, a newline, etc.)
	public static function toString(o:Object, delim:String): String
	{
		// Gather all properties
		var ret:String = "";
		for (var s:String in o)
		{
			ret = ret + s + "=" + o[s] + delim;
		}
 
		// If we gathered any, hack off the last delim
		if (ret.length > 0)
		{
			ret = ret.substr(0, ret.length-delim.length);
		}
		return ret;
	}
}
 
var person:Object = {first:"John", last:"Smith", age:22};
log(ObjectUtils.toString(person, ", ")); // first=John, last=Smith, age=22, 
 
trace(Objectutils); // ArgumentError: Error #1063

Remember: you won’t get a compiler warning or error when you write this kind of code. You might not explicitly ever log out the literal name of a class like ObjectUtils, but you might log out a Class variable you get passed as parameter. That’s what I did. I hope you won’t.