What is the recommended way to use preprocessor directives?

Hello, I am looking for an insight into a recommended way to using preprocessor directives.

In my project, I use both the Unity Assertions (Unity Scripting API) and the Unity Profiler (Unity Manual). Both of them, I use as it is shown in the examples of their respective pages. However, I don’t understand how they behave when I don’t want them to be present.

In the Scripting API for Unity Assertions, it says:

From this, I get that if I do not define UNITY_ASSERTIONS, then my assertion calls aren’t included in my compilation. However, what happens to the function call itself? See this one:

public void Initialize(){
    Assert.IsTrue(someCondition);
}

If I do not define UNITY_ASSERTIONS, what happens to this function call? Does it stick around, but doesn’t do anything or is it completely erased from the compiled code? My question aims at doing this:

public void Initialize(){
#if UNITY_ASSERTIONS
    Assert.IsTrue(someCondition);
#endif
}

Is it necessary to do this or is it redundant? If it is redundant, why? From my point of knowledge, the function call still exists, it just doesn’t do anything because since once the symbol is undefined, it becomes hollow, not doing anything.

This question also leads me to my next one. In Platform Dependent Compilation (Unity Manual), they talk about the ConditionalAttribute Class of C-Sharp. If I understand it correctly, I would not do:

public bool MyEditorValidation(){
#if UNITY_EDITOR
    // validating things for editor stuff
#endif
}

but instead I would write it like this:

[Conditional("UNITY_EDITOR")]
public bool MyEditorValidation(){
    // validating things for editor stuff
}

Is this recommend to do once you have functions that should not be present entirely in your game, only in the editor and how does it relate to my previous question in this thread, about functions being stripped of their lines, but the function call itself remaining?

I always thought that assertions were inlined in your code. So if Unity_Assertions is false, this would generate no code and your Compiler conditional is redundant. I couldn’t however, find any documentation on this on short notice.

I seem to dimly remember that you can’t build production code that includes Unity.Editor, so the conditionals should suffice.

This attribute strips all calls to function from the build asseblies, but the function itself still goes into build and may be invoked via reflection or from outside (from another app referencing your build assemblies).

This strips everything inbetween #if and #endif if constant is not defined.

All of the Unity Assert calls are defined with [Conditional("UNITY_ASSERTIONS")]. So your questions are the same question!

@palex-nx is spot on. If the #define isn’t there, calls to the method gets removed at compile time. Info is here.

Thank you for your responses, guys!

In the following, I try to summarize what I understand from your comments, please correct me if I am wrong at some point.

  • If I use the ConditionalAttribute, then the compiler ignores function calls if the related symbol is not defined, which means that the functon call is not present in the final, compiled code, does not take performance therefore and whatever.
  • In addition to that, wrapping the functon call which calls a function with a ConditionalAttribute with the same symbol is redundant, because it gets ignored by the compiler anyways, right? You can find an example for this in my first post, with the Initialize() function. Wrapping the #if around the Assert function call is redundant because it gets ignored anyways, once that symbol is undefined?
  • Last but not least, in my first post, I also make the example of using MyEditorValidation() with all of its content wrapped in a preprocessor directive. My question here is, should one do that? Let’s say I have an editor-only function (ContexMenu validation or whatever) with a ConditionalAttribute, then I wrap all of the content, all lines, of that function with the same symbol in a #if. Is this necessary or a good approach? Asking because I see this a lot, especially for custom editor attributes like ReadOnlyAttribute. They always wrap a lot of stuff in #if UNITY_EDITOR.

#3 is not right. Lets try one more time. ConditionalAttribute strips calls to function, but function body goes into build untouched. On the other hand, #if strips the inside code from build. The example

[Conditional("UNITY_EDITOR")]
public void PrintAssetPath(UnityEngine.Object asset) {
  Debug.WriteLine(AssetDatabase.GetAssetPath(asset));
}

This construction is invalid and won’t compile because while calls to this functio stripped from the all other code in project, the function itself goes into build and AssetDatabase is editor only class. You will get compilation error if you try to build this.

public void PrintAssetPath(UnityEngine.Object asset) {
#if UNITY_EDITOR
  Debug.WriteLine(AssetDatabase.GetAssetPath(asset));
#endif
}

This will work because the code of function is stripped from the build.

#if UNITY_EDITOR
public void PrintAssetPath(UnityEngine.Object asset) {
  Debug.WriteLine(AssetDatabase.GetAssetPath(asset));
}
#endif

And this will not work because function is stripped from the build, but the calls to it are not so you will get compilation error here too.

1 Like

Thank you, I get it now!