Conditional Compilation Symbols GUI (preprocessor symbols)
See original GitHub issueVisual 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:
To solve this problem, I suggest that the symbols textbox be replaced with a list GUI like the following mockup for C# projects:
For comparison, see also the preexisting list GUI for “Environment variables:” in the “Debug” panel in Project Properties of an ASP.NET Core project:
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++:
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
- Open the Project Properties window of a project.
- Click “Build” on the left.
- Look for the textbox “Conditional compilation symbols”.
- Notice how awkward this textbox is, especially when it contains more symbols than fit in such a narrow textbox.
- 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:
- Created 3 years ago
- Reactions:1
- Comments:6 (3 by maintainers)
@tmeschter wrote:
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).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
symbolRe 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 symbolEXPERIMENTAL
, 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 symbolEXPERIMENTAL
with both debug and release settings, I’d be forced to create 4 Configurations:But now, for example, I also need to test
EXPERIMENTAL
with and without WebGL – theUNITY_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: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: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
symbolIn 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 theUNFINISHED
symbol, and then the app successfully compiles and runs. Later the same day, I need to redefine theUNFINISHED
symbol in order to resume work on the unfinished code sections. Thus frequent changes occur to the enable/disable status of theUNFINISHED
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:
@verelpode I have a couple of questions, and the answers will help us better understand your needs.
The current UI is based on the assumption that the number of conditional compilation symbols is generally small, and rarely changed.