Output formatters: different approaches

During the review of the output formatters library, there were suggested several alternative approaches. For example, Gennadiy thinks the library is too complicated, and Hartmut suggests creating a library dual to Spirit -- which would be extra powerfull. That's not all. Independently, I've talked with Vaclav Blazek, who's the author of the Teng text template engine (http://teng.sourceforge.net/), which is also a similiar domain -- it's too about formatting objects. It would be great if we had some common foundation, so that I could output ptr_vector<Function> using both a simple formatter, or a flexible one, or even some template engine. Such foundation can be pretty simple: 1. A fixed set of type "categories" (sequence, map, tuple, something else) and a mechanism to obtain the category for a specific type. The current library even has some mechanism, but I'm not sure if's as simple as possible and is extentable. 2. A mechanism to iterate over elements of composite type. After some though, I believe that the mechanism should be boost::serializaton. Take, for example, sequences. The reviewed version of the library contains the code to handle boost:array, vector, list, and pair. The amount of code devoted for this is significant. If serialization library were used (it provides 'save' and 'load' functions for those types), the implementation would be simpler: The basic formatter could look like: class formatter { template<class T> void write(T &t, is_primitive) { os << t; } template<class T, class Category> void write(T &t , Category { os << start_delimiter<Category>(); os << t; os << end_delimiter<Category>() } template<class T> formatter& operator&(const T& t) { write(t); } }; The idea of the library, as I see it, is to provide object serialization, but - without the overhead serialization library has - with extra layout tweaks I don't see why it's necessary to reinvent the object traversal code which is already in boost::serialization. For example, boost::serialization support scoped_ptr. It would not make sense to add separate support for scoped_ptr in outfmt. And, as I've already mentioned I'd like the 'serialize' approach even for class members. Even if serialization headers which provide support for vectors, lists and so on drag too many dependencies, I think this is fixable. On the top of this, it's easy to provide various output facilities. - A simple multi-line indenting formatter. No customization at all, no overhead - A more advanced solution which uses nested formatters (like the revieved version), and stores formatting information in iword/pword - An interface with template system: e.g. Template t(...); vector<Function> f; t["functions"] = f; would traverse 'f' creating a tree of values which can be used in template. Thoughs? - Volodya

Vladimir Prus wrote:
During the review of the output formatters library, there were suggested several alternative approaches. For example, Gennadiy thinks the library is too complicated, and Hartmut suggests creating a library dual to Spirit -- which would be extra powerfull.
That's not all. Independently, I've talked with Vaclav Blazek, who's the author of the Teng text template engine (http://teng.sourceforge.net/), which is also a similiar domain -- it's too about formatting objects.
I will try to take a look at it next week.
It would be great if we had some common foundation, so that I could output ptr_vector<Function> using both a simple formatter, or a flexible one, or even some template engine.
2. A mechanism to iterate over elements of composite type. After some though, I believe that the mechanism should be boost::serializaton.
This sounds nice, but I don't know how achievable it is. Basically, when writing a composite type, you might want to write things in-between. Like, for a pair, you might want to write: [first, second] or <<first | second>> (where first and second are the members of the pair) Same goes for each composite type. I'm not very familiar with boost::serialize - still it is something to think about ;)
Take, for example, sequences. The reviewed version of the library contains the code to handle boost:array, vector, list, and pair. The amount of code devoted for this is significant. If serialization library were used (it provides 'save' and 'load' functions for those types), the implementation would be simpler: The basic formatter could look like:
class formatter { template<class T> void write(T &t, is_primitive) { os << t; } template<class T, class Category> void write(T &t , Category { os << start_delimiter<Category>(); os << t; os << end_delimiter<Category>() } template<class T> formatter& operator&(const T& t) { write(t); } };
The idea of the library, as I see it, is to provide object serialization, but - without the overhead serialization library has - with extra layout tweaks
Yes, it would be nice.
I don't see why it's necessary to reinvent the object traversal code which is already in boost::serialization. For example, boost::serialization support scoped_ptr. It would not make sense to add separate support for scoped_ptr in outfmt.
I would need to delve further into boost::serialize to have an oppoinion - and the unfortunate thing is that I won't have any available time soon :(
- A more advanced solution which uses nested formatters (like the revieved version), and stores formatting information in iword/pword
Yes
- An interface with template system: e.g.
Template t(...); vector<Function> f; t["functions"] = f;
would traverse 'f' creating a tree of values which can be used in template.
I'm not sure I understand. Could you give a more detailed example? Best, John -- John Torjo -- john@torjo.com Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.4 - save_dlg - true binding of your data to UI controls! + easily add validation rules (win32gui/examples/smart_dlg)

"John Torjo" wrote:
Vladimir Prus wrote:
2. A mechanism to iterate over elements of composite type. After some
though,
I believe that the mechanism should be boost::serializaton.
This sounds nice, but I don't know how achievable it is. Basically, when writing a composite type, you might want to write things in-between. Like, for a pair, you might want to write: [first, second] or <<first | second>> (where first and second are the members of the pair)
Same goes for each composite type.
Here's the kind of approach I was pursuing to allow composite types to represent their structure. It's a bit bulky, but quite general. template<typename T> struct is_composite { static const bool value = false; }; For a user-defined Dog class: template<> struct is_composite<Dog> : composite_type< Dog, element_by_functor<NameTag, Dog, std::string, DogNameGetter>, element_by_field<WeightTag, Dog, float, &Dog::weight_>, ... > { }; ( Macros could make this easier: BEGIN_COMPOSITE_TYPE(Dog) ADD_FUNCTOR_ELEMENT(std::string, DogNameGetter); ... END_COMPOSITE_TYPE(Dog); ) This information could be extracted by a Dog-formatter as follows: out << "[Dog: " << get_element<NameTag>(d) << "]"; Or if we assume the order of fields is known: out << "[Dog: " << get<0>(d) << "]"; Jonathan
participants (3)
-
John Torjo
-
Jonathan Turkanis
-
Vladimir Prus