Boost logo

Boost :

From: Ivan Vecerina (ivec_at_[hidden])
Date: 2006-04-23 14:04:02


"Marcin Kalicinski" <kalita_at_[hidden]> wrote in message
news:e2g6hi$q6v$1_at_sea.gmane.org...
: I know get/put functions in general serve two orthogonal tasks: (1)
access
: by path, and (2) type conversion. Please note that these tasks are also
: split in the interface:
:
: get_child() does only (1)
: get_own() does only (2)
: get() does first (1) and then (2).

The above alone brings questions:

- when doing (1), I wouldn't want to pay for the support for multi-level
  descent using paths. I (and my teams) have used such libraries a lot,
  and 100% of our usage have been to go down 1 level at a time.
If I never use paths, will I have to pay for multi-level paths ?
 [ code size, performance, and possibly restrictions on element names,
   maybe an additional path class ??? ]
I would not want to, I hope that you can propose a design that doesn't
impose this.

- can I define ptree<->instance conversions for a UDT ?
Let me make up a plausible example: I want to describe a graph or GUI
in a config file, and in several location I use the following type
to represent a position:
  struct Pos { int x, y; };
Obviously I do not want to read two individual fields everytime.
And for readability, I want the point to be translated into
a node with two values:
    { x: 235 y: 456 } # syntax in DataTree lib for a record
Alternatively, similar types could be stored as an array of
values:
    ( 235, 456 ) # syntax in DataTree lib for an array

I want Pos to be a first-class citizen, a value that can easily
be converted to/from a ptree (a ptree node) -- beacause I will
be storing such value in several locations (parser back-end is
irrelevant here).
What exactly do I need to do to achieve this ?
Can this be explained in the documentation ?

Preferably, I would be using an s11n archive-like object to
write once a function that can do both input and output.
This doesn't have to be part of the original ptree submission,
but I need to see that it could be added later without pain.

: > 1) value <-> ptree conversion templates
: >
: > void set( const Value& v, ptree& storage );
: > void get( Value& v, ptree const& storage ); //throws if conv. fails
:
: These functions could be made more generic by operating only on data
stored
: in ptree. They do not need the whole tree, because they do not use
paths.

If I cannot define a node<-->struct conversion and use it the same
way as a double, abstraction is killed, and ptree loses most of its
interest IMO.

: > The default implementation of these functions would use
: > lexical_cast to store/retrieve a value to/from a ptree
: > with only an 'own' value set.
: > The template could of course be specialized for user-defined types.
:
: You can already do that. You have to provide your own
inserter/extractor,
: and specialize it for the types you want. Alternatively, you can provide
: stream operations for your types (i.e operator << and >>), in this case
you
: do not have to do anything else.

I would probably implement ostream << Pos (pretty-printed for debug
output
only). But I want to define i/o to a ptree node independently of this.

: > Ambiguous keys
:
: It might be useful in some contexts to make find function throw if there
is
: more than one key with specified name. On the other hand, it would then
be
: quite hard to get a value for any instance of that key. The reverse
: operation (i.e. find does not throw but I still want to simulate
throwing
: behaviour) is easy. Just do that:
:
: if (pt.count(key) > 1) throw ...;

But if I am using paths, I would have to do this for every step along
the path???? Not acceptable.

: I think the deciding point is "if in doubt, do as std containers do". In
: this case what std::multimap does.

std::multimap does not provide operator[], because the result of this
operation would potentially be ambiguous. std::multimap::find returns
the first occurence of the searched key, which explicitly allows to
check for subsequent items (in a sorted sequence).

If you want to do "as containers do", you have to either:
 - allow only one entry per key (as std::map does)
 - do not allow direct element access if multiple values
   can have the same key.
For me the only reasonable course of action in case of an ambiguity
in a ptree path is to throw an exception / fail as if the value
was not present. Or you will cause bad surprises for end-users.

: Thank you for the time you spent preparing this far reaching proposal.
: Looking at the practical side of things, you must be aware that
implementing
: that, and getting all corner cases right would require months. How can
you
: be sure that the end result would be significantly better than what we
have
: now? I think you can do everything you want with the current version,
the
: only difference is in syntax.

Thank you Marcin for all the effort you have put in preparing this
valuable submission. I find the proposed approach to offer a common
denominator for xml/json/etc to be of great value in itself.

However, the value<->ptree conversion part, in my opinion, is not
acceptable as it is -- yet. If you provide a well-rounded, coherent,
member interface that implements >=90% of needs and is cleanly
extensible, I will agree with it. But for now, I find that the
interface is lacking, and I think that others also expressed
specific issues and disagreements with parts of the interface.

I also think that others have suggested that ptree should be
considered as a special kind of container, and I do not dislike
the idea, because so far I have not seen a consistent and
complete member interface for value i/o.

The last thing I would want to have is a library where I have
to juggle with an inconsistent mix of member and non-member
functions.

Kind regards,
Ivan

-- 
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form

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