Tuesday, 21 January 2014

My C# (Unity3D) Assert()/Log() signature combines Conditional and pre-processor

Someone queried my logging method signature in a patch I offered recently so I thought I'd share the technique and explanation.  Forewarnings:

  • it's C# (WHAT?! When did I switch? Explanation to come, I guess!)
  • it's for performance (so sacrifices some immediate clarity to that mistress).


#if !DEBUG
    [System.Diagnostics.Conditional("UNITY_EDITOR")]
#endif
    public static void Assert(bool comparison, string messageFmt, params System.Object[] args) { ... }
    // also used on logging


An explanation in two parts, (1) the Conditional and (2) how the #if interacts with it.


1. The Conditional is processed by the CLR virtual machine.  When the condition it includes is true (i.e. UNITY_EDITOR is defined), the method is invoked normally; else the call-site (where the method is invoked), is removed from the instruction flow -- it's as if the method call never existed!  You can see how this has benefits for performance!
Normally, obviously this would mean "logging in Editor, not outside".

2. By couching the above within a the "#if !DEBUG" we say only do this if DEBUG is *NOT* set.  The result is that when DEBUG *IS* set, the method always exists and looks just like a normal method (and the call-sites look normal, too).

Thus the two together mean Debug builds and the Editor get logging but non-Debug builds only have logging in the Editor.

EDIT: Sadly, "Debug builds" here doesn't mean simply clicking the "Debug Build" option in the Build Settings. Instead, one must add "DEBUG" to the "Scripting Define Symbols" (search in the "Platform Dependent Compilation" page).

LMK if you see errors or have concerns, queries, ideas, suggestions, etc.

No comments:

Post a comment