Unity 5.1 Assertion Library

There’s a great article by Yegor Bugayenko called Need Robust Software? Make It Fragile. It’s about Fail Fast philosophy where you should write your code in the way that your application will fail as fast as possible if something is significantly wrong with your data or environment.

When you’re building a mobile game with Unity then most probably you’re eager to set Script Call Optimization to Fast But No Exceptions option, as soon as you’re sure that you can do it.

Fast But No Exceptions option is hidden in Edit -> Project Settings -> Player menu (Other Settings/Optimization section). By selecting this option your code will be stripped from the exception handling code in a favor of better performance. By enabling this option you’re also taking a great risk. From now on, any exception will immediately crash your game and you won’t even know what was the cause (crash log may be not so helpful at the time).

Knowing what the stake is, you may want to enable Fast But No Exceptions option only when you’re pretty sure that your game won’t throw a single exception not ever once. There’s a plenty of situations when something may go wrong. Moreover, if you’re not the only person working in the project, the risk is even greater. It’s really easy to get NullReferenceException when your MonoBehaviour script setup requires reference to some other game objects and somebody will delete those from the scene.

Don’t assume anything

Don’t assume that your script is set up correctly. Be a pessimist and think of worst case scenario all the time. Let’s take this script for example:

public class Plane : MonoBehaviour {
    public Airport airport;

    void Update() {
        if (Vector3.Distance(airport.transform.position, transform.position) < 1000) {
            Land();
        }
    }

    // ...
}

This is a very basic example on how the Plane may interact with an Airport. I think you already know what I am going to say. This code will break if there’s no airport set. This is the case where we assumed that anyone who is working on the scene will be careful enough to connect all the references between the objects. It’s not so easy, because the Unity won’t give anyone any error or warning when they don’t connect all the references unless they run the scene and see the exception (that says very little for non-programmer person).

when_you_assume

OK, let’s try to make this script a little more self-aware. We want it to make a noise when something is wrong with it. In order to do that, I will use MonoBehaviour.OnValidate() message. OnValidate() is called:

  • In the editor without the need of entering the play mode
  • when any script value is changed
  • when the scene is loaded

So the script may now look like this:

public class Plane : MonoBehaviour {
    public Airport airport;

    void OnValidate() {
        if (airport == null) {
            Debug.LogError("Airport is set to null", this);
        }
    }

    void Update() {
        if (Vector3.Distance(airport.transform.position, transform.position) < 1000) {
            Land();
        }
    }

    // ...
}

That will print error messages to the console that something is wrong while playing with your game in the editor, and for most cases this will be good enough. However, you may also want to check if the airport is not null on the runtime (OnValidate() function works only in the editor).

public class Plane : MonoBehaviour {
    public Airport airport;

    void OnValidate() {
        CommonValidate();
    }

    void Update() {
        CommonValidate();

        if (Vector3.Distance(airport.transform.position, transform.position) < 1000) {
            Land();
        }
    }

    void CommonValidate() {
        if (airport == null) {
            Debug.LogError("Airport is set to null", this);
        }
    }

    // ...
}

OK, you’re now quite sure that your game is not throwing any exceptions, and all the validations are causing some (small, but still) overhead. How to get rid of it? Maybe preprocessor will help?

public class Plane : MonoBehaviour {
    public Airport airport;

    void OnValidate() {
        CommonValidate();
    }

    void Update() {
#if UNITY_EDITOR
        CommonValidate();
#endif

        if (Vector3.Distance(airport.transform.position, transform.position) < 1000) {
            Land();
        }
    }

    void CommonValidate() {
        if (airport == null) {
            Debug.LogError("Airport is set to null", this);
        }
    }

    // ...
}

OK, that’s pretty lot of code for such simple task. Maybe there’s another way?

Asserts to the rescue!

If you’re Unity 5.1 (or above) user, then you can take advantage of the new assertion libraryIt’s really easy to use and all needed functions can be found inside the Assert class. Let’s use it instead of a simple null-check.

public class Plane : MonoBehaviour {
    public Airport airport;

    void OnValidate() {
        Assert.IsNotNull(airport);
    }

    void Update() {
        Assert.IsNotNull(airport);

        if (Vector3.Distance(airport.transform.position, transform.position) < 1000) {
            Land();
        }
    }

    // ...
}

As you can see, I’ve used Assert.IsNotNull(). This function tells that I am expecting the value to be not-null and if it is null then I’d like to know about it.

Asserts have some advantages over manual checking:

  • Simple and readable code
  • Error messages are clean and readableassert error message
  • By default asserts are stripped off when building the game is in non-development mode (you don’t need to use preprocessor).

If you want asserts to be included in your build (asserts are not exceptions by default) then all you need to do is to define UNITY_ASSERTIONS in Script Define Symbols that can be found in Edit -> Project Settings -> Player menu. Asserts are not breaking the execution; assets will just print the error and the execution will continue. If you want it to act just as exceptions (breaking the execution), make sure to set Assert.raiseExceptions to true from your code.

And remember, the asserts may be used anywhere in your code (it doesn’t have to be at the beginning of Update), but it is a good practice to check as many things as possible before the actual code is executed. Fail fast and be safe!

related
BasicsTips
Use icons to see invisible object on scene
Your game scene may consist of objects that are visible on your scene view (like mesh) and...
0
BasicsTips
Hold the Ctrl key to snap objects to the grid
Did you know that when you hold the Ctrl key in the Scene view while moving the object its...
0
GuideIntermediateTutorial
Coroutines in Unity – Encapsulating with Promises [Part 3]
  In the last part of the series we’re going to build a real example of a REST API...
5
Call The Knights!
We are here for you.
Please contact us with regards to a Unity project below.



The Knights appreciate your decision!
Expect the first news soon!
hire us!