Boost logo

Boost :

From: Tom Bachmann (e_mc_h2_at_[hidden])
Date: 2007-03-17 12:18:32


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

[I hope I'm on the right list..]

I have been trying to extend Boost.Program_options, and I found this
very hard. I'd like to let you know of the problems I'm experiancing.

Basically, I am writing a relatively long-running program, with lots of
options. I want to be able to change these options at run-time, for
doing so, I want to create a "preferences" window or such, and (of
course) I want to reuse the options description I already created to
parse the command line and config file options.
In my vision, things would work like this:

po::options_description generic ("generic options");
generic.add_options () // e.g. --help, --version
...
po::options_description sub1 ("options for module 1");
...
po::options_description sub2 ("options for module 2");
...

po::options_description preferences_options;
preferences_options.add (sub1). add (sub2);

...
// do normal parsing (command line, config file, ...)
...

preferences_dialog pref (preferences_options);

...

An open question is, when to propagate the options. My program works in
some sort of main-loop, at the beginning of which I do

pref.commit (vm); // save options, like store would do, but overwrite
                  // and remember all options that changed
if (pref.changed ("foo-option"))
  take care of this // e.g. reload something
...

The preferences dialog should have one tab per option group (that is,
one for "options for module 1" and one for "options for module 2").
Every of that tabs should display widgets to manipulate the respective
options, that is, for every option, it's name, help information, some
sort of input widget, maybe a reset button if there's a default value.

Trying to implement all this, I encountered several problems. I'll try
to make a list of things that have to be possible, and discuss all items
in turn.

1 change the values of options in a variables_map
2 find out the type of an option
3 convert from an option value (stored in a Boost.Any) to some screen
  representation
4 find out what options in a po::options_description are members of what
  option groups

1 change the values of options in a variables_map

The only way to do this (as far as I can see) is the private interface
that the store function uses. I currently do

const_cast<boost::program_options::variable_value&> (vm[opt -> long_name
()]).value () = val;

which is neither clean nor complete (the internal reference to
value_semantic is not updated, but this should not be necessary anyway,
I think).
The easiest fix would be to add a public interface to change the value
of an option in a variables map, by making op[] return a non-const
reference. I'm not sure if code should be added to call semantic ->
notify automically.

2 find out the type of an option

This is not strictly necessary, but I'd be nice to e.g show a checkbox
for bool options, a spin button for numeric options, and an entry field
for other options. I currently infer the type by querying the Boost.Any
that holds the option, potentially after applying the default value.
This is not foolproof, however, because it fails for options that have
no default value and that have not been set before.

3 convert from an option value to some screen representation

This is not strictly necessary either, but it'd be nice to show the user
the current value of an option ;). This is some sort of "backward parse"
and can be easily put into the value_semantic class. Afterall, this is
already done, when converting the default value into a string. It is,
however, not strictly something one would usually expect from the
value_semantic class. Currently I take the type information I already
have (see 2), cast to the respective type and then convert using
Boost.Lexical_cast. This is quiet cumbersome, because I need to know
every possible type in advance and (automatically) instantiate code for
every such type and dynamically dispatch to the right code (this is the
main reason I created the dispatcher mentioned in another mail of mine).

4 find out what options in a po::options_description are members of what
  option groups

This is necessary to group the options in multiple tabs. Again, there
are only private interfaces to access the information.

All in all, I think the use of private (friend) interfaces overly
restricts the reusability of Boost.Program_options. I don't know if what
I try is in the scope of what should be possible, but I'm happy to
discuss the problems I reported, both from the perspective of changing
the library and from the perspective of changing my demands.

And I have a (unrelated) suggestion for an improvement: add an auxiliary
functor for validating. Often there are certain conditions imposed on
the options, e.g. a numeric option has to be in some interval or such.
This checking can be done once after parsing, but it'd be cleaner to
directly incorporate it. One could encode all the information in the
type, but that'd be ugly. Using Boost.Lambda, I could imagine a syntax like:

po::checked_value<int> (_1 > 0 && _1 < 5)

instead of

po::value<checked_val<int, bounds_checker<int, 1, 4> > > ()

(where I overloaded validate for checked_val's to apply the functor
encoded in the type).
- --
- -ness-
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFF/BTYvD/ijq9JWhsRAsA4AKCBbigeh/fa3k1jEBKTmJ01JPz1FwCfQE7J
3CQIyp/rRMQb4VFnQqHR3Kg=
=FRtW
-----END PGP SIGNATURE-----


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