Boost logo

Boost :

From: Hadriel Kaplan (hadrielk_at_[hidden])
Date: 2022-06-24 12:21:39


[sorry this turned out to be a long email – hopefully my lovely corporate IT-approved mail client from some company in Redmond won’t botch this up]

Ahh, right you want concrete examples of what one would need/do with this thing.

Because yeah, it’s not to convert to a string name. People already do that, as we all know.

OK, so here are some uses in my employer’s codebase – I’ll just list the first 10 I find, in the order my editor finds them:

  1. A container of event-collectors, where the enum key represents event types, and the collectors are objects that stream them to various places or save them to files, etc., per type of event.
  2. A container of loggers, where the enum key represents a logging type, and each logger is an object with its own log-level, filenames, etc.
  3. A container of subprocess execution commands, where the enum key represents the command type, and the object knows the actual command string, args , etc.
  4. A container of hashmaps, that map some VRF prefixes to some internal stuff, and the enum key represents route-advertisement types. (we’re a router company)
  5. A container of test-inputs/outputs, where the enum key represents the test-input type, and the test-inputs are various routing messages we use in tests. (there’s actually a whole big bunch of these use-cases, so I’ll skip the rest)
  6. A container of worker threads, where the enum key represents the thread name+purpose, and the thread is dedicated for that work. (used in a thread-chain)
  7. A container of timer-wheels, where the enum key represents the resolution of the timer-wheel.
  8. A container of stats/counters, where the enum key represents a specific stat/counter purpose. (there’s a whole bunch of these too, so I’ll skip the rest)
  9. A container of another enum type, where the enum key represents some internal components, and the enum values represent their current state. (up, down, disabled, etc.)
  10. A container of function objects, where the enum key represents a rule/action to take, and the function objects perform it.

I skipped a bunch of self-similar ones in there, to give a better idea. Some of these are essentially global containers, and some are members of other objects.

Obviously we could have created separate C++ variables for each instance instead, instead of using an std::array – because basically we’re using the enum key as a form of programmatic “name” for variables.

The reason we do it this way instead, however, is because when you have many of these things it is far easier to write generic code to handle them this way.

For example stats/counters: of course at the point in the code that needs to increment/decrement them, that line of code has to identify a specific stat it wants to increment/decrement/whatever, and using an enum to do so vs. variable name is not much different. But when you write the observers of those stats, that need to iterate over them to write them somewhere else, or display them, or reset them all, or whatever, it’s a lot more convenient if they’re already in a container. That code doesn’t need to know variable names. It doesn’t even need to know specific enum values. It just has to know how to access the container. And we have thousands of stats (as do our competitors, and other industries too I’m sure). Obviously some people “register” individual stats into observers, which is fine too, but we don’t need to do that for every stat.

Same goes for test inputs/outputs. We don’t write every test by-hand, for each and every test-input/output we need. We just have generic tests that iterate over all inputs, and verify all outputs. (again, I’m sure a lot of people do this – it’s impractical to do otherwise)

The other advantage to using enums for these types of things, is once you have some mechanism to convert enums-to-strings, you can use those strings too for the generic code aspects. For example in the test inputs/outputs, the enum’s string is used to print out what’s being tested and is written to the test log, so if it fails we know which one. (googletest does this as well anyway via their macros stringizing stuff, but I’m just mentioning it) Another example is that array of threads – the enum strings become the thread string names used in logging for those threads, for example.

And you can do the reverse too – if you can convert strings-to-enums, then you can use strings to find/match entries in those arrays – strings such as might be in your config for example, or even from a command-line.

-hadriel

From: Boost <boost-bounces_at_[hidden]> on behalf of Richard Hodges via Boost <boost_at_[hidden]>
Date: Friday, June 24, 2022 at 12:31 AM

I understand that presenting the type with the look and feel of a container
is somehow pleasing. The ability might be an interesting academic goal.

I am more interested in what real-world use-cases this solves.

boost.describe, wise_enum etc solve the case where (for example) I wish to
serialise and deserialise my enum value as text. This is useful in the real
world as, for example, it allows me to easily and reliably implement a JSON
communications protocol that contains my enum.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk