yaml-cpp icon indicating copy to clipboard operation
yaml-cpp copied to clipboard

Add an `into()` operator on `Node` to do optional assignment.

Open psigen opened this issue 3 years ago • 5 comments
trafficstars

It would be useful to have an into() operator on the Node class modeled off the get_to() operator in the popular nlohmann::json library. (See: https://github.com/nlohmann/json#basic-usage)

This operator assigns a casted value to an existing variable if that node has a defined value, and otherwise leaves the variable unchanged. It returns true if the variable was overwritten and false if the variable was unchanged.

This operator is extremely useful in applications where YAML is being used as a configuration source that overrides default values coming from another source, e.g.:

struct MyConfig {
  int foo = 4;
  double bar = 5.0;
  std::string baz = "six";
};

MyConfig config;
node["foo"].into(config.foo);
node["bar"].into(config.bar);

if (!node["baz"].into(config.baz))
  std::cerr << "Using default value for .baz!" << std::endl;

This removes a lot of the boilerplate associated with optionally filling in a value from a YAML. Without this operator, we have to do the following:

MyConfig config;
if (!node["foo"].IsDefined())
  config.foo = node["foo"].as(config.foo);
if (!node["bar"].IsDefined())
  config.bar = node["bar"].as(config.bar);
[...]

psigen avatar Dec 15 '21 17:12 psigen

Implemented in https://github.com/jbeder/yaml-cpp/pull/1069

psigen avatar Dec 15 '21 17:12 psigen

Thanks for filing. Reiterating here for other observers: I'm so-so on the utility of this, but if enough people thumbs-up the issue, then I'll merge the PR.

jbeder avatar Dec 15 '21 17:12 jbeder

This is major for us, and would save us from spending a lot of time creating many nearly duplicate config files for many slightly different client and server configurations, which are hard to maintain. I've used the override style of configuration very successfully on past multiple projects, with other non-YAML file formats, and not having it in yaml-cpp is painful. If you haven't had the pleasure of benefitting from the utility of it, I assure you it's out there.

Besides allowing a base config file, and then separate override config files to tweak things for the different setups, it also allows easy injection of override values from the command line.

In this example command line, -c specifies a config file, and -o specifies a YAML string to pass to the config loader:

MyApplication.exe -c standard_config.yaml -c segment_2_config_override.yaml -o "thread_count: 10" -o "pool_size: 100000"

In both types of option, multiples are all passed to the YAML config loader, in order of appearance on the command line. into() would make this much easier.

Without this feature, we're stuck creating either dozens or hundreds of nearly identical config files (and then tasked with keeping them up to date when one common value needs to be changed in all of them), or complicating the code with the optional loading described by psigen above.

Pentamix avatar Dec 21 '21 14:12 Pentamix