question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Conditional Compilation Symbols GUI (preprocessor symbols)

See original GitHub issue

Visual Studio Version: 16.8.2

Summary

Visual Studio is a truly wonderful product, but some aspects of it cause hassles every week on average. Currently the GUI for Conditional Compilation Symbols in Project Properties window in Visual Studio (16.8.2) is inadequate and a hassle to use, and inconsistent with other parts of Visual Studio. It fails to support large projects that need a larger quantity of symbols. It is unfortunately only a textbox (and narrow), despite the fact that it actually represents a list of values. The current textbox suggests that only a single value should be entered, but in reality it’s a case of a textbox being misused as a substitute for a list GUI. Screenshot:

image

To solve this problem, I suggest that the symbols textbox be replaced with a list GUI like the following mockup for C# projects:

image

For comparison, see also the preexisting list GUI for “Environment variables:” in the “Debug” panel in Project Properties of an ASP.NET Core project:

image

C# versus C++ Differences/Considerations

In C#, a symbol can only be enabled or disabled (boolean), whereas in C++, a value can be assigned to a symbol. I began my career using C++ but I mostly stopped using C++ long ago because I noticed that my productivity was much better when I used C#, thus the GUI for C++ projects is unimportant for me, but anyway, for people who still use a lot of C++ code, remember that C++ symbols allow a value to be assigned to each symbol. Thus the GUI for C++ symbols should be like the above “Environment variables” screenshot, whereas the GUI for C# symbols can be a list of tickboxes/checkboxes. Here is a mockup for C++:

image

Alternatively, you may wish to use the same symbol list GUI for both C# and C++ projects. This is also a good idea. Thus the symbol list would look like the above two-column mockup regardless of whether it is for a C# or C++ project. However, if it is a C# project, Visual Studio would limit the user to entering only a boolean true or false value for each symbol (not an integer value). If it is a C++ project, Visual Studio would allow the symbol value to be true or false or an integer.

Example C++ Code Value in new GUI in VS
#define EXPERIMENTAL true
#undef EXPERIMENTAL (or otherwise not defined) false
#define XYZ_VERSION 5001 5001

Re Multiple Configurations in a project

Regarding multiple Configurations in a .csproj (such as the “Debug” and “Release” Configurations), the list/names of Conditional Compilation Symbols should be the same for all Configurations, except that the tick/value of the symbols should be different for each Configuration. For example, the symbols DEBUG and TRACE should appear in the symbol list regardless of whether the current Configuration is “Debug” or “Release”, but when the “Release” configuration is chosen, the DEBUG symbol would be shown as unticked or Value=false. Thus when you use the GUI to view a different configuration, only the tick or value of each symbol should change, not the symbol names nor the quantity of symbols.

Alternatively, if compatibility reasons or other reasons lead to a final decision to store a completely separate symbol list for each Configuration, then this would still be OK provided it has the ability to enable and disable each symbol without deleting symbols from the list.

Steps to Reproduce

  1. Open the Project Properties window of a project.
  2. Click “Build” on the left.
  3. Look for the textbox “Conditional compilation symbols”.
  4. Notice how awkward this textbox is, especially when it contains more symbols than fit in such a narrow textbox.
  5. Notice how VS does not provide any way to disable a symbol without deleting it from the textbox.

Expected Behavior

  • Support a larger quantity of symbols, for example 10-20 symbols, in a manner that isn’t awkward or inconvenient or a hassle.
  • Support the ability to enable and disable symbols without deleting them from the Project Properties window.
  • Preferably show only different values (not names) of symbols when the user views a different Configuration. Preferably have the same list of symbol names for all configurations, but different symbol values for each Configuration.
  • Respect the standard practice of using a list GUI to represent a list, instead of using a textbox to represent a list.
  • Be consistent with other parts of Visual Studio, such as the aforementioned “Environment variables” GUI.
  • Use a self-explanatory GUI. Do not use “secret” non-intuitive practices in GUI, such as visually appearing to support only a single item (a single textbox) but actually supporting multiple items if the user knows the special “secret” such as using special punctuation (semicolons) to separate multiple items in the textbox.
  • Do not require users to continue to remember the details of special punctuation rules such as whether the names in the textbox should be separated by space, comma, or semicolon. Do not confuse users whenever users accidentally use a comma or space instead of a semicolon. Use a self-explanatory list GUI instead of hidden/special punctuation rules.

Actual Current Behavior

  • A larger quantity of symbols (such as 10-20 symbols) is not truly supported in practice. Technically it is supported but it is impractical, especially considering how narrow the textbox is.
  • Whenever you need to temporarily disable a symbol, you’re forced to entirely delete it from the textbox, meaning there is no way to temporarily disable a symbol without deleting it.
  • The GUI (that textbox) is a non-standard way of representing a list of items, and it is inconsistent with other parts of Visual Studio.

User Impact

  • Large projects need a larger number of symbols but the narrow textbox makes it difficult for users to manage more than 2 or 3 symbols.
  • Users are mistakenly led to believe that Visual Studio doesn’t really support large projects, because this part of the GUI is currently designed for only 2 or 3 symbols.
  • Users lose information whenever they need to temporarily disable a symbol, because VS forces users to entirely delete the symbol instead of allowing symbols to be disabled. Users suffer loss of productivity when they later re-enter the symbol and accidentally enter the symbol name slightly different than it was previously. For example, users can’t remember that the EXACT name of the previously-deleted symbol was (for example) “WINDOWS_UWP” and not “UWP”. Users temporarily delete “WINDOWS_UWP” and then later accidentally re-enter it as “UWP”, causing time lost to troubleshooting.
  • Users (even experienced users) are confused whenever they forget that the special “secret” punctuation is semicolons, and they accidentally enter commas or spaces instead of semicolons.
  • New users or beginners need “secret” knowledge to know how to enter multiple items in the textbox, because the GUI is not self-explanatory and not intuitive.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:1
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
verelpodecommented, Dec 3, 2020

@tmeschter wrote:

“The current UI is based on the assumption that the number of conditional compilation symbols is generally small, and rarely changed.”

I disagree that the current UI assumes that the symbols are rarely changed. The current UI has a tickbox “Define TRACE constant” – this tickbox implies that TRACE is frequently changed (or at least more than rarely changed).

image

In my opinion, the current UI’s attitude toward frequent changes is a self-contradictory “Yes but also No” attitude. The TRACE tickbox implies frequent changes but the symbols textbox implies rare changes, thus it’s currently self-contradictory.

I’ll answer your question anyway. In my opinion, the assumption you mentioned was only valid in the past, or only valid with small simple projects, or perhaps it was never valid even for small projects (considering TRACE). For example, the Unity3D manual lists 40 symbols, and the MS documentation page “#if (C# reference)” lists 33 symbols (an incomplete list; more than 33 MS symbols exist), and other projects likewise involve 10-40 symbols, and my work also uses approx 20 symbols, yet the current UI is only practical for approx 3 symbols.

An example: The EXPERIMENTAL symbol

Re frequency of changes, for example in my previous screenshots I made a symbol named EXPERIMENTAL, and I realize people might suggest that I create a new Configuration named “Experimental” that defines the symbol EXPERIMENTAL, and I realize that I could then use the preexisting Config chooser control to frequently and easily switch between Configs named “Experimental”, “Debug”, and “Release”, but this technique is broken. Should a new Config named “Experimental” be configured with settings suitable for debugging or for release? In order to test the symbol EXPERIMENTAL with both debug and release settings, I’d be forced to create 4 Configurations:

Config Name Symbols Defined
Debug DEBUG; TRACE;
Release TRACE;
Experimental Debug EXPERIMENTAL; DEBUG; TRACE;
Experimental Release EXPERIMENTAL; TRACE;

But now, for example, I also need to test EXPERIMENTAL with and without WebGL – the UNITY_WEBGL symbol described in the Unity3D manual (actually I don’t use Unity3D in real life, rather I have a bunch of other symbols, but I’ll use Unity3D as an example). So now I’m forced to create 8 Configs:

Config Name Symbols Defined
Debug DEBUG; TRACE;
Release TRACE;
Experimental Debug EXPERIMENTAL; DEBUG; TRACE;
Experimental Release EXPERIMENTAL; TRACE;
Debug with WebGL UNITY_WEBGL; DEBUG; TRACE;
Release with WebGL UNITY_WEBGL; TRACE;
Experimental Debug with WebGL UNITY_WEBGL; EXPERIMENTAL; DEBUG; TRACE;
Experimental Release with WebGL UNITY_WEBGL; EXPERIMENTAL; TRACE;

But wait, I also need to test the program with and without the IL2CPP-based script-compiler – the ENABLE_IL2CPP symbol also described in the Unity3D manual. So now I’m forced to create 16 Configs – this is highly unmanageable and messy:

Config Name Symbols Defined
Debug DEBUG; TRACE;
Release TRACE;
Experimental Debug EXPERIMENTAL; DEBUG; TRACE;
Experimental Release EXPERIMENTAL; TRACE;
Debug with WebGL UNITY_WEBGL; DEBUG; TRACE;
Release with WebGL UNITY_WEBGL; TRACE;
Experimental Debug with WebGL UNITY_WEBGL; EXPERIMENTAL; DEBUG; TRACE;
Experimental Release with WebGL UNITY_WEBGL; EXPERIMENTAL; TRACE;
Debug with IL2CPP ENABLE_IL2CPP; DEBUG; TRACE;
Release with IL2CPP ENABLE_IL2CPP; TRACE;
Experimental Debug and IL2CPP ENABLE_IL2CPP; EXPERIMENTAL; DEBUG; TRACE;
Experimental Release and IL2CPP ENABLE_IL2CPP; EXPERIMENTAL; TRACE;
Debug with WebGL and IL2CPP ENABLE_IL2CPP; UNITY_WEBGL; DEBUG; TRACE;
Release with WebGL and IL2CPP ENABLE_IL2CPP; UNITY_WEBGL; TRACE;
Experimental Debug with WebGL and IL2CPP ENABLE_IL2CPP; UNITY_WEBGL; EXPERIMENTAL; DEBUG; TRACE;
Experimental Release with WebGL and IL2CPP ENABLE_IL2CPP; UNITY_WEBGL; EXPERIMENTAL; TRACE;

Add one more symbol and you need 32 Configs.

But wait, I work with multiple .csproj’s in real life. I need these 32 Config’s in all of the .csproj’s. So I’d be forced to spend hours recreating 32 Config’s in multiple different .csproj’s that all need the same list of 32 Config’s (alternatively I could manually edit the XML inside each .csproj file and hope I don’t make any mistakes).

See, that doesn’t work. What’s needed is a listbox of symbols with tickboxes or a “Value” column, so each symbol can be individually enabled or disabled independently of other symbols, frequently and easily. Even better would be if the symbol names list (without values) could be shared between multiple .csproj’s (such as via the preexisting MSBuild <Import> element).

Another example: The UNFINISHED symbol

In my previous screenshots I also made a symbol named UNFINISHED. Often I need to compile and run (with or without VS debugger) the very latest dev-build of the program, but it cannot be compiled because of some unfinished new classes or methods. So I wrap the unfinished portions with #if UNFINISHED and undefine the UNFINISHED symbol, and then the app successfully compiles and runs. Later the same day, I need to redefine the UNFINISHED symbol in order to resume work on the unfinished code sections. Thus frequent changes occur to the enable/disable status of the UNFINISHED symbol.

Class Libraries (or Nuget Packages) versus Apps

I believe it’s also important to consider the difference in usage characteristics of class libraries (or nuget packages) versus apps. Developers who develop class libraries and/or nuget packages may well need to change the symbols more frequently than app developers, in order to support multiple variations of the same library or nuget package.

Before publishing a new version of a nuget package, the developer(s) want to test that every variation still works correctly, and this means enabling and disabling symbols each time a new version of the library will be published, i.e. frequently. Again using Unity3D as an example, Unity3D is a class library, so the Unity3D developers would want to frequently enable and disable various combinations of the following symbols, to test Unity3D prior to publishing each new version:

Conditionally-Compiled Feature Symbol Name
Whether WebGL is supported UNITY_WEBGL
Whether Analytics are performed UNITY_ANALYTICS
Whether the IL2CPP script-compiler is supported ENABLE_IL2CPP
Whether “Unity Editor scripts” scripts are supported UNITY_EDITOR
Unity library for .NET Standard NET_STANDARD_2_0
Unity library for .NET Framework 4.6 NET_4_6
Unity library for .NET Legacy NET_LEGACY
etc etc
etc etc
etc etc
Whether the UI is excluded (for Console and Server programs)
Whether the UI is compiled for WPF
Whether the UI is compiled for WinUI 3
Whether the UI is compiled for UWP/WinRT
Whether the UI is compiled for Xamarin UI
Whether the UI is compiled for Mono-WinForms
0reactions
tmeschtercommented, Dec 2, 2020

@verelpode I have a couple of questions, and the answers will help us better understand your needs.

  1. Do you frequently change the conditional compilation symbols?
  2. If so, why do you change them?

The current UI is based on the assumption that the number of conditional compilation symbols is generally small, and rarely changed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

C# preprocessor directives
Defining symbols​​ You use the following two preprocessor directives to define or undefine symbols for conditional compilation: #define : Define ...
Read more >
Conditional Compilation
There are a number of built-in scripting symbols which allow you to selectively compile or omit code based on the selected Platform, the...
Read more >
NETCOREAPP3_1 preprocessor symbol is not defined ...
NET 5, conditional compilation symbols would be cumulative. In .NET 5 RC2 and later, projects only define symbols for the target framework ...
Read more >
c# - Dynamically set conditional compilation symbols
I would like to have a list of conditional compilation symbols, maybe a table where each symbol has a checkbox, and then at...
Read more >
Short Unity tip: conditional compilation with custom ...
Short Unity tip: conditional compilation with custom preprocessor ... Scroll down until you see the text box “Scripting Define Symbols”.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found