solutions to resolve enum field naming restriction in Google protobuf due to C++

14,351

The prevailing solution in existing code is option (2): give each enumerant name a prefix corresponding to its type. This also helps reduce collisions with macros. It's verbose, but unlike the other options suggested, it has no runtime overhead and it creates the least confusion for people reading the code.

(FWIW, Cap'n Proto has escaped this problem by using C++11 enum classes. It's unlikely that protobufs will ever do this since it would break existing code.)

(Disclosure: I am the author of Cap'n Proto as well as of most of Google's open source Protobuf code.)

Share:
14,351

Related videos on Youtube

wonhee
Author by

wonhee

Senior software engineer@Blizzard Entertainment, mainly Java/Spring backend development at work. Self-motivated lifelong learner for interesting topics through a variety of MOOC. Master's degree in Computer Science at the University of Illinois Urbana-Champaign. Active student at GeorgiaTech's OMSCS as of 2021.

Updated on June 19, 2022

Comments

  • wonhee
    wonhee almost 2 years

    As you might know, when you define enums in Google protobuf either with global scope or in same message, you can't define enum field name to be same if enums are sibling.

    Even if you are going to generate Java code with proto file, protoc complains about it and doens't generate any code with following message.

    "XXX" is already defined in "your.package.name".
    Note that enum values use C++ scoping rules, meaning that enum values are siblings of their type,
    not children of it. 
    Therefore, "XXX" must be unique within "your.package.name", not just within "your_enum_name".
    

    so, which means you should do something like

    1. wrapping the colliding enums with message.
      • Pros : well... protoc doesn't fail?
      • Cons : generate code is going to have one extra static wrapper class so that it will increase SerDes cost a little bit + naming seems long enough. e.g, CURRENCY.NAMESPACE(wrapper message name).USD

    or

    1. use prefix for the field, so if your conflicting field name is UNKNOWN and it's in CURRENCY, it's going to be CURRENCY.CURRENCY_UNKNOWN or something like that.
      • Pros : simple
      • Cons : as ugly as #1, inconsistency with existing enum field naming that doesn't have any prefix.

    or

    1. Just don't use Enum. Use string type.
      • Pros : simple, don't need to define fallback enum field like UNKNOWN = 1 as default.
      • Cons : losing benefit of having enum.

    Seems like C++ 11 supports better enums that doesn't have this issue, but unfortunately latest protoc doesn't support it, and we can't simply ask other consumers to switch their side to use C++ if they are not using it.

    So, it's going to be choosing less worse solution rather than best solution, and probably we are going to use #2 at this point. Does anyone have same experience and tell me what was your solution and how is it ended up?

    • Kerrek SB
      Kerrek SB over 9 years
      Solution: Follow the vendor recommended style guide.
    • wonhee
      wonhee over 9 years
      Don't think this is the solution. For example, Foo in the sytle guide line, you can't define another FIRST_VALUE or SECOND_VALUE in a enum which is sibling with Foo. That's the issue here.
    • Deduplicator
      Deduplicator over 9 years
      They should upgrade to enum class.
    • Kerrek SB
      Kerrek SB over 9 years
      @wonhee: Ah yes, good point.
  • wonhee
    wonhee over 9 years
    That Cap'n Proto looks good except the fact that I need a solution based on protoc since it's widely used in company right now with at least three different languages.