Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

enums: leading "_"; last item ","

Discussion in 'Scripting' started by Shushustorm, May 5, 2022.

  1. Shushustorm

    Shushustorm

    Joined:
    Jan 6, 2014
    Posts:
    1,084
    Hey everyone!

    I got two questions about enums; maybe someone knows what's going on?

    1. Does it cause trouble using leading "_"s for some of the items?
    Because those characters get removed by the editor when it's serialized for the inspector. For example, "_Null" shows "Null".

    2. Placing a "," after the last item doesn't cause an error. Is this intended? Or does this even create a null after the last item? Might even be an issue when looping through an enum? If it doesn't cause trouble, though, that could be useul, since rearranging doesn't require adding and removing "," anywhere.

    Best wishes,
    Shu
     
  2. nijnstein

    nijnstein

    Joined:
    Feb 6, 2021
    Posts:
    78
    the , after the last enumeration was left in to make it easier for codegeneration

    edit, looked up the spec:

    The C# Specification (Page 355/Section 17.7) states:

    Like Standard C++, C# allows a trailing comma at the end of an array-initializer. This syntax provides flexibility in adding or deleting members from such a list, and simplifies machine generation of such lists.


    leading underscores should be avoided, many compilers use these in preprocessing and it can screw up naming.
     
    Last edited: May 5, 2022
    Shushustorm and Bunny83 like this.
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    Leading underscores do not have any special meaning in C# itself. However Unity "beautifies" variable names for display in the inspector. That is stripping leading "_" and "m_" as well as capitalising every variable name and actually splitting camelCaseVariables into seperate words. So
    m_myVariableTest
    would be displayed as
    My Variable Test
    in the inspector. This has nothing to do with how enums work in C# itself.

    Enums are just alias types for simply integral types. If no type is specified, an enum is just an int variable, nothing more. The members of an enum are just enumerated constants. The main advantage of enums is the implicit type safety. Even though it's just an integer varible, an enum does represent a seperate type. It can be simply casted to int or the other way round, but that has to be done explicitly in most cases.

    The enum members also do get implicit values if none are specified. Here's an example

    Code (CSharp):
    1.     public enum MyEnum : byte
    2.     {
    3.         Cow,       // implicit = 0
    4.         Fish,      // implicit = 1
    5.         Dog = 10,  // explicit = 10
    6.         Cat,       // implicit = 11
    7.         Bird = 5,  // explicit = 5
    8.     }
    9.  
    As you can see here we actually specified the underlaying type as byte. So a MyEnum variable is actually a byte variable. Also an enum is technically not restricted to the specified member constants. You can do

    Code (CSharp):
    1. MyEnum val = (MyEnum)42;
    and it just works fine. The enum variable "val" would contain the value 42, even though there is no constant to for this value.

    That's pretty much all there is to enums. The trailing comma was already explained by @nijnstein above.
     
    Shushustorm likes this.
  4. Shushustorm

    Shushustorm

    Joined:
    Jan 6, 2014
    Posts:
    1,084
    Thanks for the replies! That's very informative! I was aware about being able to specify ints. In fact, I am using that frequently, especially when I want to ensure data persistence, e.g. when writing files and casting the enums to ints. I'm glad about the trailing comma not being an issue! That does simplify quite a number of use cases! About the leading "_", though: So it's no issue? Or might be? I have been using those for variable names for many years, but for enums, I introduced a _Null for many use cases not too long ago, just to make sure it can be set to "nothing" as well. Granted, "None" would have done as well, but now I put "Null" all over the place with a leading "_" to make sure it's not read as "null" in whichever scenario this might happen.
     
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    As I said from a pure code and serialization point of view leading underscores do not cause any issues as they are valid characters in identifiers. It's a pure visual thing inside Unity. Actually I always use either "None", "Unknown" or whatever may be appropriate depending on the context. "Invalid" may also come to my mind. But again, it depends what the enum actually represents logically. I can't really think of anything where "Null" would be appropriate since enums do not represent references, not even remotely and as you said, it would be way more confusing. The confusion comes from the name itself and adding an underscore does not really change that confusion.

    I usually use "None" for bitmasks because it indicates that none of the options apply. It also indicates implicitly that maybe multiple may apply at the same time. "Unknown" / "Uninitialized" / "Invalid" usually applies to any kind of state. Though as already mentioned it depends on the context which makes the most sense. We use words to convey a meaning. If we have a type enum to specify the kind of mob, we may have "Cat", "Dog" and "Unspecified" or "Unknown". "Null" seems to be just out of context.

    Though in anyway that default value should always be value "0". Yes, there are some cases, especially when dealing with APIs where the valid values may start at 0 and an invalid state may be represented by
    -1
    , but those are rare exceptions. You definitely should never call the value
    -1
    "Null" ;)
     
    Shushustorm and nijnstein like this.
  6. nijnstein

    nijnstein

    Joined:
    Feb 6, 2021
    Posts:
    78
    About leading underscores, from the iso c++ draft: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf:

    "In addition, some identifiers are reserved for use by C ++ implementations and shall not be used otherwise; no diagnostic is required. (a) Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use. (b) Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace."

    Seeing a lot of code in unity written c# will end up being compiled in an il2cpp tool chain i just would never use them even though names will probably be translated
     
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    This is unnecessary and counterproductive :) C# has a language specification and unless their IL2CPP framework specify restrictions, there's no reason to add artifical restrictions based on assumptions.

    In fact, as you can read in this blog about IL2CPP, Unity does perform its own name mangling.

    Code (CSharp):
    1. // UnityEngine.Vector3
    2. struct Vector3_t78
    3. {
    4. // System.Single UnityEngine.Vector3::x
    5. float ___x_1;
    6. // System.Single UnityEngine.Vector3::y
    7. float ___y_2;
    8. // System.Single UnityEngine.Vector3::z
    9. float ___z_3;
    10. };

    The il2cpp.exe utility has converted each of the three instance fields, and done a little bit of name mangling to avoid conflicts and reserved words. By using leading underscores, we are using some reserved names in C++, but so far we’ve not seen any conflicts with C++ standard library code.

    So avoiding leading underscores would have no benefit. In fact a lot C# developers use an underscore for private instance fields. I still prefer
    m_
    as prefix because the underscore can easily be overlooked, depending on the IDE and what kind of underlining it may show.
     
  8. nijnstein

    nijnstein

    Joined:
    Feb 6, 2021
    Posts:
    78
    As your spoiler state extra effort was taken to avoid conflicts. And so far no conflicts were found. Seeing much is experimental these days i wouldnt call it counterproductive to just avoid them.
     
  9. Shushustorm

    Shushustorm

    Joined:
    Jan 6, 2014
    Posts:
    1,084
    Thanks for your detailed replies, @Bunny83 and @nijnstein !

    @Bunny83
    Alright, that's great leading underscores don't cause any trouble!
    I am using "_Null" for initialization, it's supposed to represent "no state". And I did also get used to how it looks, since the underscore is clearly visible, so it's easier to find enums within the code. "Uninitialized" would probably the most descriptive, but, then again, I'm not really going to type that all the time; so "None" might have been the alternative. Anyway, for consistency, I'll keep using "_Null". Also, interesting that you mention -1! I do actually set "_Null" to -1, so that valid values are starting from 0, which makes it easy to access values from arrays. At least so far, that hasn't caused any trouble.
    Otherwise, I am using leading underscores for self reference:
    GameObject _obj = this.gameObject; rather than
    GameObject thisObj = this.gameObject;