[Dune] ParameterTree

Jö Fahlke jorrit at jorrit.de
Sun Jan 30 22:22:07 CET 2011


Am Fri, 28. Jan 2011, 15:02:10 +0100 schrieb Carsten Gräser:
> If you use
> 
>   T t = pTree.get("key", expression);
> 
> what you really want will almost always be the string->T conversion.
> Instead of this the string->typeof(expression) conversion is used.
> For example the user might expect
> 
>   double x = pTree.get("key", 0);
> 
> to parse the value as double which is not done. In this case it's
> safe because you get an exception. In others it need not to be safe.

OK, I think I understand your argument better now.  But by the same argument
you would have to disallow the "/"-operator and force everyone to use
something like

  template<class T> struct Forward { typedef T type; };
  template<class T> T div(typename Forward<T>::type nominator,
                          typename Forward<T>::type denominator);

because

  ctype h = 1/elements_per_dimension;

is not doing what people expect.

I know there are a lot of places where I did choose the overload by the type
of the default value; I would have to change all of them, and I'm sure I'm not
the only one.  This is a C-derived language and we can expect programmers to
be aware of this kind of trap, so I don't think it is worth the effort.

> >>> methods were sometimes implemented as overloads made this the only reliable
> >>> way.  I consider The fact that most of these overloads are provided by a
> >>> method template an implementation detail.
> >> In my opinion it provides a natural way to select a type: using a template parameter.
> >>
> >>> Instead I propose specialize the ParameterTree::Parser struct for char to read
> >>> a numerical value instead of a character.
> >> You might also want the character depending on your application.
> >> The main reason to forbid the implicit type determination is that
> >> similar unexpected behaviour might appear if the user defines the
> >> conversion for custom types.
> > 
> > If you want the character, you can always read a std::string, check that it's
> > size exactly 1 and take it's first character.  If we keep it as it is, and you
> > want the numerical value, you can convert the default value to an int and
> > convert the return value back to a char, while checking that the return value
> > actually fits in a char.  Either way you make it a litte harder for some
> > poeple, and I don't care much which way we choose.  I believe that it is a
> > little more likely that people want the numerical value for a char (I've run
> > into the same problem before...)
> > 
> > As to custom conversions, do you mean IO-conversions (operator<<) or type
> > conversions here?  In both cases I don't see a problem that could be solved by
> > specifying the conversion type explicitly.
> 
> Currently you can simply specialize Parser<A> and Parser<B> such that
> the constructer A(B) exists and is commenly used. If you don't have
> 
>   Parser<A>::parse(string)  == (A)(Parser<B>::parse(string))
> 
> the following will not do the same
> 
>   B b;
>   A a1 = pTree.get("key", b);
>   A a1 = pTree.get<A>("key", b);
> 
> while the later is what you want in most cases.

Nor would I expect them to do the same, necessarily.  In fact I wouldn't even
expect those two to do the same:

  A a;
  A a1 = pTree.get("key", a);
  A a2 = pTree.get<A>("key", a);

On the other hand, I don't see how the existance of the specializations

  template<> class Parser<A>;
  template<> class Parser<B>;

can influence the existance of a constructor of A that takes B as an argument,
or the existance of any other conversion from A to B, for that matter, so I
may have missed your point here.

Maybe this is about the following: If you have a template function and an
exact overload

  template<class T> T get(const std::string &name, const T &defaultValue);
  double get(const std::string &name, double defaultValue);

then for

  get("key", float(0));

the function template is selected, while you would expect the non-template
function to be selected?

>                                                 One example would be the following:
> Suppose you have specialized Parser<R> for some type R for exact rational numbers
> that can e.g. be constructed from double. Then
> 
>   R r = pTree.get<R>("key", 0.0):
> 
> will result in r==1/10 while
> 
>   R r = pTree.get("key", 0.0);
> 
> will result in r!=1/10.

I would write that as

  R r = pTree.get("key", R(0.0));

>                         Further examples are
> 
>  std::vector<int> v;
> 
>  long long ll = pTree.get("key", v.size());

  long long ll = pTree.get("key", (long long)(v.size()));

>  std::cout << ll << std::endl;
> 
>  std::cout << pTree.get("key", v.size()) << std::endl;

I'm not sure which overload you mean here.

>  int i        = pTree.get("key", v.size());

  int i        = pTree.get("key", int(v.size()));

>  std::cout << i << std::endl;
> 
> Guess what happens for key=-1. Only the last one prints -1, funny, isn't it?

Well, and

  std::cout << 1/3 << std::endl;

will print 0.  And actually, your calls to get() should throw exceptions
because "-1" cannot be parsed as an unsigned value of type std::size_t.


You are right that you have the make sure that the type of the defaultValue is
the one you actually want to use for the parsing.  If it isn't, you have to
explicitly convert it.  On the other hand, if that value is alreay of the
correct type, there is not need to specify the type again.  For instance, I
like to collect my default values somewhere at the top of my programs or
another designated place

  // default values
  unsigned global_refines = 0;

and later I overwrite them with a value read from configuration

  int main() {
    // ...
    global_refines = params.get("global_refines", global_refines);
    // ...
  }

If you have your way, I would have to explicitly write params.get<unsigned>().
Should I later introduce a special meaning for global_refines==-1, I would
have to change its type to int.  But then it is easy to forget to change the
type in the call to get() too, so there are some pitfalls here as well.

-- 
Interpunktion, Orthographie und Grammatik der Email ist frei erfunden.
Eine Übereinstimmung mit aktuellen oder ehemaligen Regeln wäre rein
zufällig und ist nicht beabsichtigt.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 828 bytes
Desc: Digital signature
URL: <https://lists.dune-project.org/pipermail/dune/attachments/20110130/7d69718c/attachment.sig>


More information about the Dune mailing list