[fusion] [intro] ADAPT_STRUCT extensions

Hi, in the discussion about the library I called "Intro" at the time it has been suggested to use BOOST_FUSION_ADAPT_STRUCT of Boost.Fusion for data member access. based on that I'd like to propose two extensions to ADAPT_STRUCT, which I think are useful beyond my use case: 1) ADAPT_STRUCT can adapt public data members only. with the modifications I uploaded here: http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/ all data members can be adapted. for example: class A{ private: friend class fusion::access; int a; }; BOOST_FUSION_ADAPT_STRUCT(A,(int,a) ) 2) adaption of a class including its base class members. for example: struct A{ int a; }; struct B{ int b; }; struct C : A,B{ int c; } BOOST_FUSION_ADAPT_STRUCT(A,(int,a) ) BOOST_FUSION_ADAPT_STRUCT(B,(int,b) ) BOOST_FUSION_ADAPT_DERIVED( C, (A)(B), (int,c) ) an instance of C is now a fusion sequence of size 3. http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/ada... private inheritance is supported as above, virtual inheritance is not. I'm not sure if virtual inheritance can be supported.

in the discussion about the library I called "Intro" at the time it has been suggested to use BOOST_FUSION_ADAPT_STRUCT of Boost.Fusion for data member access.
based on that I'd like to propose two extensions to ADAPT_STRUCT, which I think are useful beyond my use case:
1)
ADAPT_STRUCT can adapt public data members only.
with the modifications I uploaded here: http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/
all data members can be adapted. for example:
class A{ private: friend class fusion::access; int a; };
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) )
2)
adaption of a class including its base class members. for example:
struct A{ int a; }; struct B{ int b; }; struct C : A,B{ int c; }
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) ) BOOST_FUSION_ADAPT_STRUCT(B,(int,b) ) BOOST_FUSION_ADAPT_DERIVED( C, (A)(B), (int,c) )
an instance of C is now a fusion sequence of size 3. http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/a dapt_derived.hpp
private inheritance is supported as above, virtual inheritance is not. I'm not sure if virtual inheritance can be supported.
Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities which allow using (member-) functions instead of direct access to the data members of a class/struct? Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com

Zitat von Hartmut Kaiser <hartmut.kaiser@gmail.com>:
1)
ADAPT_STRUCT can adapt public data members only.
with the modifications I uploaded here: http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/
all data members can be adapted. for example:
class A{ private: friend class fusion::access; int a; };
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) )
2)
adaption of a class including its base class members. for example:
struct A{ int a; }; struct B{ int b; }; struct C : A,B{ int c; }
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) ) BOOST_FUSION_ADAPT_STRUCT(B,(int,b) ) BOOST_FUSION_ADAPT_DERIVED( C, (A)(B), (int,c) )
an instance of C is now a fusion sequence of size 3. http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/a dapt_derived.hpp
private inheritance is supported as above, virtual inheritance is not. I'm not sure if virtual inheritance can be supported.
Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities which allow using (member-) functions instead of direct access to the data members of a class/struct?
no I had not, I was using 1.41. where can I see those? can't seem to find them in 1.43 or the trunk. do these solve one of the two issues above? in case you brought it up because then you could have public accessor functions to private members, I'd still propose to add a way to adapt private members as shown above. I'd like to use this for what is apparently known as the "scrap your boilerplate" pattern in the functional programming world (see the previous [intro] discussion), which requires adapting each member in every class used in such an algorithm. there obviously shouldn't be public accessors for all members. best, Stefan

On 7/30/2010 6:35 AM, Stefan Strasser wrote:
Zitat von Hartmut Kaiser <hartmut.kaiser@gmail.com>:
1)
ADAPT_STRUCT can adapt public data members only.
with the modifications I uploaded here: http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/
all data members can be adapted. for example:
class A{ private: friend class fusion::access; int a; };
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) )
2)
adaption of a class including its base class members. for example:
struct A{ int a; }; struct B{ int b; }; struct C : A,B{ int c; }
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) ) BOOST_FUSION_ADAPT_STRUCT(B,(int,b) ) BOOST_FUSION_ADAPT_DERIVED( C, (A)(B), (int,c) )
an instance of C is now a fusion sequence of size 3. http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/a dapt_derived.hpp
private inheritance is supported as above, virtual inheritance is not. I'm not sure if virtual inheritance can be supported.
Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities which allow using (member-) functions instead of direct access to the data members of a class/struct?
no I had not, I was using 1.41. where can I see those? can't seem to find them in 1.43 or the trunk.
do these solve one of the two issues above? in case you brought it up because then you could have public accessor functions to private members, I'd still propose to add a way to adapt private members as shown above. I'd like to use this for what is apparently known as the "scrap your boilerplate" pattern in the functional programming world (see the previous [intro] discussion), which requires adapting each member in every class used in such an algorithm. there obviously shouldn't be public accessors for all members.
I like it! I think this patch provides solutions not yet available. You should coordinate with Christopher Schmidt, he did the new adapt class macros and figure out how to make it all fit and have a consistent interface. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman schrieb:
On 7/30/2010 6:35 AM, Stefan Strasser wrote:
Zitat von Hartmut Kaiser <hartmut.kaiser@gmail.com>:
1)
ADAPT_STRUCT can adapt public data members only.
with the modifications I uploaded here: http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/
all data members can be adapted. for example:
class A{ private: friend class fusion::access; int a; };
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) )
2)
adaption of a class including its base class members. for example:
struct A{ int a; }; struct B{ int b; }; struct C : A,B{ int c; }
BOOST_FUSION_ADAPT_STRUCT(A,(int,a) ) BOOST_FUSION_ADAPT_STRUCT(B,(int,b) ) BOOST_FUSION_ADAPT_DERIVED( C, (A)(B), (int,c) )
an instance of C is now a fusion sequence of size 3. http://svn.boost.org/svn/boost/sandbox/intro/boost/fusion/adapted/struct/a
dapt_derived.hpp
private inheritance is supported as above, virtual inheritance is not. I'm not sure if virtual inheritance can be supported.
Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities which allow using (member-) functions instead of direct access to the data members of a class/struct?
no I had not, I was using 1.41. where can I see those? can't seem to find them in 1.43 or the trunk.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not documented yet. For more information, refer to the code and the testcases: https://svn.boost.org/trac/boost/browser/trunk/boost/fusion/adapted/class https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence/ada...
do these solve one of the two issues above? in case you brought it up because then you could have public accessor functions to private members, I'd still propose to add a way to adapt private members as shown above. I'd like to use this for what is apparently known as the "scrap your boilerplate" pattern in the functional programming world (see the previous [intro] discussion), which requires adapting each member in every class used in such an algorithm. there obviously shouldn't be public accessors for all members.
I like it! I think this patch provides solutions not yet available. You should coordinate with Christopher Schmidt, he did the new adapt class macros and figure out how to make it all fit and have a consistent interface.
I patched the code in the trunk to enable the adaption of private attributes. The adaptee just needs to friend "struct boost::fusion::extension::access". See changeset 64490 (https://svn.boost.org/trac/boost/changeset/64490) for details. Regarding the second feature request: I am not in favor of adding yet another set of BOOST_FUSION_ADAPT_xxx-macros. Altogether we got 6 documented and 4 undocumented macros to adapt structs, 10 undocumented macros to adapt classes and another 4 macros to define structs. Any new adaption family will multiply the macro count, disfigure the common code base of the macros even more, bloat the documentation and most likely will not raise the learning curve for developers. I think, rather than introducing a new set of macros to adapt class hierarchies, this specific usecase may be covered in a convenient way using a composition of more primitive means. In particular the segmented sequences might come in handy. Any class hierarchy may be represented by a n-ary segmented fusion wrapper sequence. struct A{int x;}; struct B{int y;}; struct C : A,B{int z;}; BOOST_FUSION_ADAPT_STRUCT(A, (int,x)) BOOST_FUSION_ADAPT_STRUCT(B, (int,y)) BOOST_FUSION_ADAPT_STRUCT(C, (int,z)) struct adapted_C : fusion::tree<C&, A&, B&> { adapted_C(C& c) : fusion::tree<A&, B&, C&>(c,c,c){} }; int main() { C c;c.x=0;c.y=1;c.z=2; adapted_C adapted_c(c); std::cout << fusion::flatten(adapted_c) << std::endl; } To get native fusion support without a named wrapper, the tree-view may be constructed inplace whenever an intrinsic sequence operation is performed. Defining such functionality may be hidden behind a new macro. struct A{int x;}; struct B{int y;}; struct C : A,B{int z;}; BOOST_FUSION_ADAPT_STRUCT(A, (int,x)) BOOST_FUSION_ADAPT_STRUCT(B, (int,y)) BOOST_FUSION_ADAPT_STRUCT_NAMED_NS(C, BOOST_PP_EMPTY(), C_adpt, (int,z)) typedef fusion::tree<C_adpt, A&, B&> tree_type; BOOST_FUSION_ADAPT_INPLACE( //type to adapt C, //type to construct *inplace* whenever an intrinsic //sequence operation is performed tree_type, //initialization expression, with obj being C&, the instance of //C fusion::repeat<3>(fusion::single_view<C&>(obj))) ) int main() { C c;c.x=0;c.y=1;c.z=2; std::cout << fusion::flatten(c) << std::endl; } BOOST_FUSION_ADAPT_INPLACE is simple to implement - and it is just one new, independent macro. If compiled using a recent optimizing compiler, there will not be any runtime overhead at all. Unfortunately the segmented sequences are undocumented and pretty much broken at the moment. I will definitely work on them once I have time again. I think, whenever compile-time is not mandatory, new facilities should be aligned to the functional fundamental of Fusion that is: providing independent, primitive means that can be used to compose new, more expressive means. Does that make sense? -Christopher

Zitat von Christopher Schmidt <mr.chr.schmidt@online.de>:
I patched the code in the trunk to enable the adaption of private attributes. The adaptee just needs to friend "struct boost::fusion::extension::access". See changeset 64490 (https://svn.boost.org/trac/boost/changeset/64490) for details.
great! one small thing, could you change "struct access" to "class access"? MSVC complains if the key differs between the definition and the friend declaration, and I think people are more used to "friend class" (in general, and because of "class serialization::access") is there a rationale for the "extension" namespace somewhere online? anything that uses the extension mechanism is in the extension namespace?
Regarding the second feature request: I am not in favor of adding yet another set of BOOST_FUSION_ADAPT_xxx-macros.
struct A{int x;}; struct B{int y;}; struct C : A,B{int z;}; BOOST_FUSION_ADAPT_STRUCT(A, (int,x)) BOOST_FUSION_ADAPT_STRUCT(B, (int,y))
I understand the problem, but I don't think we have a solution yet. thanks for the idea with segmented sequences, but it looks like a workaround to me, because what does...:
BOOST_FUSION_ADAPT_STRUCT(C, (int,z))
...mean? it says that it adapts the struct C, but it doesn't adapt C, it adapts the most-derived-level of C. is there even a use case for this? why would you want to do that? if there isn't you could say that ADAPT_STRUCT can not be used for derived classes. you need another macro. adapting the whole struct C the way you suggested would always require writing (if I hide all your code behind 1 new macro): BOOST_FUSION_ADAPT_STRUCT_NAMED(C,BOOST_PP_EMPTY(),C_derlevel, (int,z) ) BOOST_FUSION_ADAPT_ALL_OF_STRUCT(C,C_derlevel,(A)(B) ) I'd prefer adding new macros to that, e.g. ADAPT_SUBCLASS. wrt a solution without adding new macros I only see one using C99 variadic macros. do you know what's the state of those? last I checked the compilers I use implemented them, and I think they will be part of c++0x because they are part of C99. but there was also a bug in MSVC's implementation which I don't know can be worked around. with variadic macros the adaption of C could look like this: BOOST_FUSION_ADAPT_STRUCT(C, (A) (B) (int,z) ) with no new macros. Stefan

On Sat, Jul 31, 2010 at 9:02 AM, Christopher Schmidt < mr.chr.schmidt@online.de> wrote:
Joel de Guzman schrieb:
On 7/30/2010 6:35 AM, Stefan Strasser wrote:
Zitat von Hartmut Kaiser <hartmut.kaiser@gmail.com>:
Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities which allow using (member-) functions instead of direct access to the data members of a class/struct?
no I had not, I was using 1.41. where can I see those? can't seem to find them in 1.43 or the trunk.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not documented yet. For more information, refer to the code and the testcases:
https://svn.boost.org/trac/boost/browser/trunk/boost/fusion/adapted/class https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence
https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence/ada...
I think the ADAPT_CLASS macros fundamentally change the expected behavior of struct adaptation in a negative way. A non-template class/struct is a collection of a) types (declared as nested typedefs or other structs) b) values of the following variety i) static member variables (values that are non-functions) ii) static member functions (values that are functions) iii) member functions (values that are "special" functions over the instance record) c) an instance record, which includes member variables Up until this point, struct adaptation has exclusively been over the instance record, point c) above. This is very simple to understand and implies exactly one canonical adaptation for every struct/class. ADAPT_CLASS mixes point c) and point iii) in an arbitrary way. Stefan's suggestions, on the other hand, are a straightforward extension of the original semantics. I'd personally like to see the latter incorporated and the former removed. David -- David Sankel Sankel Software www.sankelsoftware.com 585 617 4748 (Office)

On 8/12/10 9:46 AM, David Sankel wrote:
On Sat, Jul 31, 2010 at 9:02 AM, Christopher Schmidt< mr.chr.schmidt@online.de> wrote:
Joel de Guzman schrieb:
On 7/30/2010 6:35 AM, Stefan Strasser wrote:
Zitat von Hartmut Kaiser<hartmut.kaiser@gmail.com>:
Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities which allow using (member-) functions instead of direct access to the data members of a class/struct?
no I had not, I was using 1.41. where can I see those? can't seem to find them in 1.43 or the trunk.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not documented yet. For more information, refer to the code and the testcases:
https://svn.boost.org/trac/boost/browser/trunk/boost/fusion/adapted/class https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence
https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence/ada...
I think the ADAPT_CLASS macros fundamentally change the expected behavior of struct adaptation in a negative way. A non-template class/struct is a collection of
a) types (declared as nested typedefs or other structs) b) values of the following variety i) static member variables (values that are non-functions) ii) static member functions (values that are functions) iii) member functions (values that are "special" functions over the instance record) c) an instance record, which includes member variables
Up until this point, struct adaptation has exclusively been over the instance record, point c) above. This is very simple to understand and implies exactly one canonical adaptation for every struct/class.
ADAPT_CLASS mixes point c) and point iii) in an arbitrary way. Stefan's suggestions, on the other hand, are a straightforward extension of the original semantics. I'd personally like to see the latter incorporated and the former removed.
What's wrong with having both? Non-intrusive class adaptation, IMO, is very important too. I like Stefan's suggestions too but I don't understand why we can't have both. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Wed, Aug 11, 2010 at 11:29 PM, Joel de Guzman <joel@boost-consulting.com>wrote:
On 8/12/10 9:46 AM, David Sankel wrote:
On Sat, Jul 31, 2010 at 9:02 AM, Christopher Schmidt< mr.chr.schmidt@online.de> wrote:
Joel de Guzman schrieb:
On 7/30/2010 6:35 AM, Stefan Strasser wrote:
Zitat von Hartmut Kaiser<hartmut.kaiser@gmail.com>:
Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities which allow using (member-) functions instead of direct access to the data members of a class/struct?
no I had not, I was using 1.41. where can I see those? can't seem to find them in 1.43 or the trunk.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not documented yet. For more information, refer to the code and the testcases:
https://svn.boost.org/trac/boost/browser/trunk/boost/fusion/adapted/class https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence
https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence/ada...
I think the ADAPT_CLASS macros fundamentally change the expected behavior of struct adaptation in a negative way. A non-template class/struct is a collection of
a) types (declared as nested typedefs or other structs) b) values of the following variety i) static member variables (values that are non-functions) ii) static member functions (values that are functions) iii) member functions (values that are "special" functions over the instance record) c) an instance record, which includes member variables
Up until this point, struct adaptation has exclusively been over the instance record, point c) above. This is very simple to understand and implies exactly one canonical adaptation for every struct/class.
ADAPT_CLASS mixes point c) and point iii) in an arbitrary way. Stefan's suggestions, on the other hand, are a straightforward extension of the original semantics. I'd personally like to see the latter incorporated and the former removed.
What's wrong with having both? Non-intrusive class adaptation, IMO, is very important too. I like Stefan's suggestions too but I don't understand why we can't have both.
I've given this some further thought and I think my problems are: a) the use of the word CLASS. This is inappropriate since that family of functions applies to a subset of classes and structs that use the getter setter idiom (GSI). b) the GSI is one of many possible idioms. One might also wish to include static member variables in the sequence, for example. c) I don't think GSI should have the same "status" as the STRUCT family since it is one of many possible idioms and one that is particularly bad (I can elaborate on why if someone wants). So, I suppose I would be in support of the CLASS family if it was renamed to GSI and put in a separate header for GSI support functions. David -- David Sankel Sankel Software www.sankelsoftware.com 585 617 4748 (Office)

David Sankel schrieb:
On Wed, Aug 11, 2010 at 11:29 PM, Joel de Guzman <joel@boost-consulting.com>wrote:
On 8/12/10 9:46 AM, David Sankel wrote:
On Sat, Jul 31, 2010 at 9:02 AM, Christopher Schmidt< mr.chr.schmidt@online.de> wrote:
Joel de Guzman schrieb:
On 7/30/2010 6:35 AM, Stefan Strasser wrote:
Zitat von Hartmut Kaiser<hartmut.kaiser@gmail.com>:
> Have you seen the new BOOST_FUSION_ADAPT_CLASS() family of utilities > which > allow using (member-) functions instead of direct access to the data > members > of a class/struct? >
no I had not, I was using 1.41. where can I see those? can't seem to find them in 1.43 or the trunk.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not documented yet. For more information, refer to the code and the testcases:
https://svn.boost.org/trac/boost/browser/trunk/boost/fusion/adapted/class https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence
https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/test/sequence/ada...
I think the ADAPT_CLASS macros fundamentally change the expected behavior of struct adaptation in a negative way. A non-template class/struct is a collection of
a) types (declared as nested typedefs or other structs) b) values of the following variety i) static member variables (values that are non-functions) ii) static member functions (values that are functions) iii) member functions (values that are "special" functions over the instance record) c) an instance record, which includes member variables
Up until this point, struct adaptation has exclusively been over the instance record, point c) above. This is very simple to understand and implies exactly one canonical adaptation for every struct/class.
ADAPT_CLASS mixes point c) and point iii) in an arbitrary way. Stefan's suggestions, on the other hand, are a straightforward extension of the original semantics. I'd personally like to see the latter incorporated and the former removed.
What's wrong with having both? Non-intrusive class adaptation, IMO, is very important too. I like Stefan's suggestions too but I don't understand why we can't have both.
I've given this some further thought and I think my problems are:
a) the use of the word CLASS. This is inappropriate since that family of functions applies to a subset of classes and structs that use the getter setter idiom (GSI). b) the GSI is one of many possible idioms. One might also wish to include static member variables in the sequence, for example. c) I don't think GSI should have the same "status" as the STRUCT family since it is one of many possible idioms and one that is particularly bad (I can elaborate on why if someone wants).
So, I suppose I would be in support of the CLASS family if it was renamed to GSI and put in a separate header for GSI support functions.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not exclusively limited to getter and setter methods. Any expression that denotes to the given lvalue or rvalue types may be used. float ff; struct S{static int T;}; float& f(S){return ff;} BOOST_FUSION_ADAPT_CLASS( S, (int&,int&,S::T,S::T)(float&,float const&,f(obj),f(obj)) ) In this regard I like 'CLASS' as it implies a somewhat public interface with a black box implementation. -Christopher

Zitat von Christopher Schmidt <mr.chr.schmidt@online.de>:
a) the use of the word CLASS. This is inappropriate since that family of functions applies to a subset of classes and structs that use the getter setter idiom (GSI). b) the GSI is one of many possible idioms. One might also wish to include static member variables in the sequence, for example. c) I don't think GSI should have the same "status" as the STRUCT family since it is one of many possible idioms and one that is particularly bad (I can elaborate on why if someone wants).
So, I suppose I would be in support of the CLASS family if it was renamed to GSI and put in a separate header for GSI support functions.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not exclusively limited to getter and setter methods. Any expression that denotes to the given lvalue or rvalue types may be used.
float ff; struct S{static int T;}; float& f(S){return ff;} BOOST_FUSION_ADAPT_CLASS( S, (int&,int&,S::T,S::T)(float&,float const&,f(obj),f(obj)) )
In this regard I like 'CLASS' as it implies a somewhat public interface with a black box implementation.
I don't think the fact that ADAPT_CLASS isn't limited to getter and setter _methods_, but allows get/set expressions, changes the argument. ADAPT_CLASS doesn't distinguish itself from ADAPT_STRUCT by what is the difference between c++ "class" and c++ "struct". I'd argue that it doesn't even adapt a class, but defines a fusion sequence from a series of c++ expressions. that might be a useful feature, and one useful variant of that feature might be a macro that defines "obj" for the scope of the expressions, but I think the naming is confusing. see my previous mail for a practical example. finding a name for this feature along the line of "define sequence from expressions" would also reduce the number of macros. I don't think the SUB-/DERIVED variants I proposed are needed for this.

On 8/13/10 3:19 AM, Stefan Strasser wrote:
Zitat von Christopher Schmidt <mr.chr.schmidt@online.de>:
a) the use of the word CLASS. This is inappropriate since that family of functions applies to a subset of classes and structs that use the getter setter idiom (GSI). b) the GSI is one of many possible idioms. One might also wish to include static member variables in the sequence, for example. c) I don't think GSI should have the same "status" as the STRUCT family since it is one of many possible idioms and one that is particularly bad (I can elaborate on why if someone wants).
So, I suppose I would be in support of the CLASS family if it was renamed to GSI and put in a separate header for GSI support functions.
The BOOST_FUSION_ADAPT_xxxCLASSxxx-macros are not exclusively limited to getter and setter methods. Any expression that denotes to the given lvalue or rvalue types may be used.
float ff; struct S{static int T;}; float& f(S){return ff;} BOOST_FUSION_ADAPT_CLASS( S, (int&,int&,S::T,S::T)(float&,float const&,f(obj),f(obj)) )
In this regard I like 'CLASS' as it implies a somewhat public interface with a black box implementation.
I don't think the fact that ADAPT_CLASS isn't limited to getter and setter _methods_, but allows get/set expressions, changes the argument.
ADAPT_CLASS doesn't distinguish itself from ADAPT_STRUCT by what is the difference between c++ "class" and c++ "struct". I'd argue that it doesn't even adapt a class, but defines a fusion sequence from a series of c++ expressions.
that might be a useful feature, and one useful variant of that feature might be a macro that defines "obj" for the scope of the expressions, but I think the naming is confusing. see my previous mail for a practical example.
finding a name for this feature along the line of "define sequence from expressions" would also reduce the number of macros. I don't think the SUB-/DERIVED variants I proposed are needed for this.
C'mon guys! We're venturing into the name-game land! If that's the game, then we should shout out why C++ confusingly has "struct" and "class" anyway which both have very little nuance. I don't want to go there. Sorry. This is not going to be another bike-shed issue. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Zitat von Joel de Guzman <joel@boost-consulting.com>:
finding a name for this feature along the line of "define sequence from expressions" would also reduce the number of macros. I don't think the SUB-/DERIVED variants I proposed are needed for this.
C'mon guys! We're venturing into the name-game land! If that's the game, then we should shout out why C++ confusingly has "struct" and "class" anyway which both have very little nuance. I don't want to go there. Sorry. This is not going to be another bike-shed issue.
the name caused both david and me to fundamentally misunderstand the macro, and I'm supposed to explain to the library user that it is the absolute wrong thing to do to adapt a class using ADAPT_CLASS. that's a lot of confusion for a still undocumented bike-shed.

On Fri, Aug 13, 2010 at 12:10:23PM +0200, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
C'mon guys! We're venturing into the name-game land! If that's the game, then we should shout out why C++ confusingly has "struct" and "class" anyway which both have very little nuance. I don't want to go there. Sorry. This is not going to be another bike-shed issue.
that's a lot of confusion for a still undocumented bike-shed.
For what it's worth, the first time I saw the macro mentioned on-list, I wondered why you needed a special macro for classes when you had a perfectly fine one for structs. Due to the fine distinction between struct/class, naming it _CLASS_ would be doing everyone a disservice as it gives it connotations it shouldn't have. As for what it should be named, I won't suggest anything, as long as it's less ambigious. -- Lars Viklund | zao@acc.umu.se

On 8/13/10 6:46 PM, Lars Viklund wrote:
On Fri, Aug 13, 2010 at 12:10:23PM +0200, Stefan Strasser wrote:
Zitat von Joel de Guzman<joel@boost-consulting.com>:
C'mon guys! We're venturing into the name-game land! If that's the game, then we should shout out why C++ confusingly has "struct" and "class" anyway which both have very little nuance. I don't want to go there. Sorry. This is not going to be another bike-shed issue.
that's a lot of confusion for a still undocumented bike-shed.
For what it's worth, the first time I saw the macro mentioned on-list, I wondered why you needed a special macro for classes when you had a perfectly fine one for structs.
Due to the fine distinction between struct/class, naming it _CLASS_ would be doing everyone a disservice as it gives it connotations it shouldn't have.
As for what it should be named, I won't suggest anything, as long as it's less ambigious.
Ok, fair enough. But as long as I don't see a better substitute, the name will stand. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On 8/13/10 6:10 PM, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
finding a name for this feature along the line of "define sequence from expressions" would also reduce the number of macros. I don't think the SUB-/DERIVED variants I proposed are needed for this.
C'mon guys! We're venturing into the name-game land! If that's the game, then we should shout out why C++ confusingly has "struct" and "class" anyway which both have very little nuance. I don't want to go there. Sorry. This is not going to be another bike-shed issue.
the name caused both david and me to fundamentally misunderstand the macro, and I'm supposed to explain to the library user that it is the absolute wrong thing to do to adapt a class using ADAPT_CLASS.
And I still don't understand the reason why. You mentioned that because it does not return a reference it should not be called a "class" adaptor. But I can't figure out why a reference to an actual object should be a requirement.
that's a lot of confusion for a still undocumented bike-shed.
I'd say the confusion stems from the lack of documentation and you guys jumping to early conclusions. Anyway... for the sake of moving forward, let me open the door to name suggestions. I can probably suggest ADAPT_ADT. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Zitat von Joel de Guzman <joel@boost-consulting.com>:
the name caused both david and me to fundamentally misunderstand the macro, and I'm supposed to explain to the library user that it is the absolute wrong thing to do to adapt a class using ADAPT_CLASS.
And I still don't understand the reason why. You mentioned that because it does not return a reference it should not be called a "class" adaptor. But I can't figure out why a reference to an actual object should be a requirement.
it isn't a sequence of values anymore but a sequence of objects that are convertible to the values. which can cause many subtle problems, among them probably some of the same as those of vector<bool>. one fusion-specific problem: struct A{ int i; }; struct F{ void operator()(int) const{ /* do something */ } template<typename T> void operator()(T) const{} }; fusion::for_each(A(),F()); //does something A a; fusion::for_each(a,F()); //does nothing. a "const" sequence is iterated as values, but a non-const sequence is iterated as proxy objects, which aren't matched to the "int"-overload.
Anyway... for the sake of moving forward, let me open the door to name suggestions. I can probably suggest ADAPT_ADT.
ADT? ADAPT_EXPR would be my suggestion, as it can also be used to make a fusion sequence out of some global variables for example.

On 8/15/10 10:22 PM, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
the name caused both david and me to fundamentally misunderstand the macro, and I'm supposed to explain to the library user that it is the absolute wrong thing to do to adapt a class using ADAPT_CLASS.
And I still don't understand the reason why. You mentioned that because it does not return a reference it should not be called a "class" adaptor. But I can't figure out why a reference to an actual object should be a requirement.
it isn't a sequence of values anymore but a sequence of objects that are convertible to the values. which can cause many subtle problems, among them probably some of the same as those of vector<bool>.
one fusion-specific problem:
struct A{ int i; };
struct F{ void operator()(int) const{ /* do something */ } template<typename T> void operator()(T) const{} };
fusion::for_each(A(),F()); //does something A a; fusion::for_each(a,F()); //does nothing.
a "const" sequence is iterated as values, but a non-const sequence is iterated as proxy objects, which aren't matched to the "int"-overload.
Here's my use case (if I haven't given it yet). If you or anyone can provide a better solution to what's provided, I'm all ears: class foo { public: int x() const; void x(int n); int y() const; void y(int n); private: // encapsulated }; Now, adapt that class to fusion.
Anyway... for the sake of moving forward, let me open the door to name suggestions. I can probably suggest ADAPT_ADT.
ADT?
Abstract Data Type.
ADAPT_EXPR would be my suggestion, as it can also be used to make a fusion sequence out of some global variables for example.
Good point. But still doesn't cut it for me. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Zitat von Joel de Guzman <joel@boost-consulting.com>:
class foo { public:
int x() const; void x(int n); int y() const; void y(int n);
private: // encapsulated };
Now, adapt that class to fusion.
is the goal a (mutable) fusion sequence with value type int? then there is no solution, as the class only exposes the value of its members. if the goal is just any representation of the class in sequence form, I'd suggest to make the (now transparent) proxy object visible to the user. that way even functors that require a reference to the value can be applied to a class, by plugging in something like template<...> struct transform_property{ template<typename T> void operator()(property<T> prop) const{ T tmp=prop.get(); base(tmp); prop.set(tmp); } }; with property<> being the proxy object. my case could then support sequences created using ADAPT_CLASS/ADAPT_whatever similarily. -Stefan

On 8/16/10 1:01 AM, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
class foo { public:
int x() const; void x(int n); int y() const; void y(int n);
private: // encapsulated };
Now, adapt that class to fusion.
is the goal a (mutable) fusion sequence with value type int? then there is no solution, as the class only exposes the value of its members. if the goal is just any representation of the class in sequence form, I'd suggest to make the (now transparent) proxy object visible to the user.
[snip] And as a matter of fact, that IS the intent. The proxy object is a public class in namespace boost::fusion::extension named class_member_proxy (terser name suggestion welcome). I hope you guys see now from the example above that it is a very typical representation of an OOP *class*. I'd say that this example is the most common form of class that needs to be adapted and that the only way to satisfy this requirement is to do it the way it is done now. It's not perfect, it's not as clean as I hoped. I too don't like proxies since C++ does not allow you to write perfect proxies. But I see no other way around. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Zitat von Joel de Guzman <joel@boost-consulting.com>:
On 8/16/10 1:01 AM, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
class foo { public:
int x() const; void x(int n); int y() const; void y(int n);
private: // encapsulated };
Now, adapt that class to fusion.
is the goal a (mutable) fusion sequence with value type int? then there is no solution, as the class only exposes the value of its members. if the goal is just any representation of the class in sequence form, I'd suggest to make the (now transparent) proxy object visible to the user.
[snip]
And as a matter of fact, that IS the intent. The proxy object is a public class in namespace boost::fusion::extension named class_member_proxy (terser name suggestion welcome).
ok, I missed the public proxy. I don't want to beat this to death, since I'm only going to use ADAPT_STRUCT the name of it is really the only thing that concerns me. so don't bother to reply to each of these points in detail, just give it another thought: - the proxy is implicitely convertible to/from values - const sequences are iterated as T, not as proxy<T const> - I think the value types of the sequence are T, not proxy<T> each of these points seem to try to hide the proxy from the user, while we agree that it can't be hidden completely. I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible. the example I used in a previous email would then outright fail until support for proxies is added, as opposed to work in one case and fail in another, very similar, case. -Stefan

On 8/16/10 8:11 AM, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
On 8/16/10 1:01 AM, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
class foo { public:
int x() const; void x(int n); int y() const; void y(int n);
private: // encapsulated };
Now, adapt that class to fusion.
is the goal a (mutable) fusion sequence with value type int? then there is no solution, as the class only exposes the value of its members. if the goal is just any representation of the class in sequence form, I'd suggest to make the (now transparent) proxy object visible to the user.
[snip]
And as a matter of fact, that IS the intent. The proxy object is a public class in namespace boost::fusion::extension named class_member_proxy (terser name suggestion welcome).
ok, I missed the public proxy. I don't want to beat this to death, since I'm only going to use ADAPT_STRUCT the name of it is really the only thing that concerns me.
so don't bother to reply to each of these points in detail, just give it another thought: - the proxy is implicitely convertible to/from values - const sequences are iterated as T, not as proxy<T const> - I think the value types of the sequence are T, not proxy<T>
each of these points seem to try to hide the proxy from the user, while we agree that it can't be hidden completely.
I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible. the example I used in a previous email would then outright fail until support for proxies is added, as opposed to work in one case and fail in another, very similar, case.
Those are very good points. I await for Christopher's reply. I think what you gave is a reasonable strategy. I like it. I really hope that despite our disagreements, we can move forward now. We really need the features that you provided that started this thread (e.g. inheritance and optional intrusive adaptation). I hope we can incorporate them into the code that we have now. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman schrieb:
On 8/16/10 8:11 AM, Stefan Strasser wrote:
Zitat von Joel de Guzman <joel@boost-consulting.com>:
[snip]
ok, I missed the public proxy. I don't want to beat this to death, since I'm only going to use ADAPT_STRUCT the name of it is really the only thing that concerns me.
so don't bother to reply to each of these points in detail, just give it another thought: - the proxy is implicitely convertible to/from values - const sequences are iterated as T, not as proxy<T const> - I think the value types of the sequence are T, not proxy<T>
each of these points seem to try to hide the proxy from the user, while we agree that it can't be hidden completely.
I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible. the example I used in a previous email would then outright fail until support for proxies is added, as opposed to work in one case and fail in another, very similar, case.
Those are very good points. I await for Christopher's reply. I think what you gave is a reasonable strategy. I like it.
I don't agree. The proxy is indeed clumsy, but due to being implicitly convertible to the underlying type it does its job quite well. In most use-cases an adapted 'class' does feel just like any other regular fusion container. In my opinion, fully exposing the proxy type is not conducive as the type of interest is always the type encapsulated by the wrapper. The proxy is just a means to an end. If the special traits of proxies are ditched, that is if the implicit conversion ability is removed and the proxy is exposed as the actual value type, all generic user code will need to handle proxy types explicitly. Generic user tmp code would probably need hacky mpl-code that distinguishes fusion proxies from non-proxy value types. Generic run-time functors would need to be specialized for proxies. That is prone to errors! With the current design, only very few run-time functors have to be specialized for proxies at all. Stefan, considering your special use-case: if the proxy's underlying value type is exposed as the real value type of the sequence, you don't need to specialize your functor at all. See the attached code - ref_for_each is an implementation of fusion::for_each that internally resolves proxy types. Such an approach hides the proxy completely! I do not see how fully exposing the proxy leads to simpler or less error prone code. Therefore I vote for keeping the interface as it is - with the proxy type being documented and its semantics fully exposed to the user. As for the name, I do like ADAPT_EXPR or ADAPT_ADT more than ADAPT_CLASS. Just my 2 cents. -Christopher

On 8/17/2010 5:10 AM, Christopher Schmidt wrote:
I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible. the example I used in a previous email would then outright fail until support for proxies is added, as opposed to work in one case and fail in another, very similar, case.
Those are very good points. I await for Christopher's reply. I think what you gave is a reasonable strategy. I like it.
I don't agree. The proxy is indeed clumsy, but due to being implicitly convertible to the underlying type it does its job quite well. In most use-cases an adapted 'class' does feel just like any other regular fusion container. In my opinion, fully exposing the proxy type is not conducive as the type of interest is always the type encapsulated by the wrapper. The proxy is just a means to an end. If the special traits of proxies are ditched, that is if the implicit conversion ability is removed and the proxy is exposed as the actual value type, all generic user code will need to handle proxy types explicitly. Generic user tmp code would probably need hacky mpl-code that distinguishes fusion proxies from non-proxy value types. Generic run-time functors would need to be specialized for proxies. That is prone to errors! With the current design, only very few run-time functors have to be specialized for proxies at all.
Also very good points. I think the proxy should behave similar to Boost ref, as it should expose an implicit conversion to T. This alone will satisfy many code that expects T. As for exposing the proxy as the value type of the sequence, you are right. However, what we can probably do is to be consistent with handling const and non-const and always return a proxy so there is no surprise when code works one way and not the other way.
Stefan, considering your special use-case: if the proxy's underlying value type is exposed as the real value type of the sequence, you don't need to specialize your functor at all. See the attached code - ref_for_each is an implementation of fusion::for_each that internally resolves proxy types. Such an approach hides the proxy completely!
I do not see how fully exposing the proxy leads to simpler or less error prone code. Therefore I vote for keeping the interface as it is - with the proxy type being documented and its semantics fully exposed to the user. As for the name, I do like ADAPT_EXPR or ADAPT_ADT more than ADAPT_CLASS.
My problem with this approach is that you need special algorithms to deal with these proxies. It may not be a bad idea to embrace proxies (and reference wrappers) library wide as intrinsic to our concepts, so that proxies will be totally transparent, but I am not quite sure if it's worth it. It's an additional burden for algorithm writers to deal with. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman schrieb:
On 8/17/2010 5:10 AM, Christopher Schmidt wrote:
I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible. the example I used in a previous email would then outright fail until support for proxies is added, as opposed to work in one case and fail in another, very similar, case.
Those are very good points. I await for Christopher's reply. I think what you gave is a reasonable strategy. I like it.
I don't agree. The proxy is indeed clumsy, but due to being implicitly convertible to the underlying type it does its job quite well. In most use-cases an adapted 'class' does feel just like any other regular fusion container. In my opinion, fully exposing the proxy type is not conducive as the type of interest is always the type encapsulated by the wrapper. The proxy is just a means to an end. If the special traits of proxies are ditched, that is if the implicit conversion ability is removed and the proxy is exposed as the actual value type, all generic user code will need to handle proxy types explicitly. Generic user tmp code would probably need hacky mpl-code that distinguishes fusion proxies from non-proxy value types. Generic run-time functors would need to be specialized for proxies. That is prone to errors! With the current design, only very few run-time functors have to be specialized for proxies at all.
Also very good points. I think the proxy should behave similar to Boost ref, as it should expose an implicit conversion to T. This alone will satisfy many code that expects T. As for exposing the proxy as the value type of the sequence, you are right. However, what we can probably do is to be consistent with handling const and non-const and always return a proxy so there is no surprise when code works one way and not the other way.
I agree.
Stefan, considering your special use-case: if the proxy's underlying value type is exposed as the real value type of the sequence, you don't need to specialize your functor at all. See the attached code - ref_for_each is an implementation of fusion::for_each that internally resolves proxy types. Such an approach hides the proxy completely!
I do not see how fully exposing the proxy leads to simpler or less error prone code. Therefore I vote for keeping the interface as it is - with the proxy type being documented and its semantics fully exposed to the user. As for the name, I do like ADAPT_EXPR or ADAPT_ADT more than ADAPT_CLASS.
My problem with this approach is that you need special algorithms to deal with these proxies. It may not be a bad idea to embrace proxies (and reference wrappers) library wide as intrinsic to our concepts, so that proxies will be totally transparent, but I am not quite sure if it's worth it. It's an additional burden for algorithm writers to deal with.
Well, that is a *lot* of work - and such an approach does not hide the proxy completely. The return type of fusion::deref is still a proxy. I think we should proxify the 'const' return type and rename BOOST_FUSION_ADAPT_xxxCLASSxxx to BOOST_FUSION_ADAPT_xxxADTxxx . BOOST_FUSION_ADAPT_xxxEXPRxxx breaks ranks as EXPR does not relate to the adaptee at all. boost::fusion::extension::class_member_proxy<T> should be changed to boost::fusion::extension::adt_attribute_proxy<T, B>, with B being a boolean constant that is true for lvalue and false for rvalue proxies. The drawbacks of proxies should be pointed out explicitly in the documentation, including a short abstract that advocates adapting abstract data types using fusion's native extension mechanism in order to avoid the proxy. Are there any objections to these changes? Stefan, is this acceptable for you? -Christopher

On 8/21/2010 2:58 AM, Christopher Schmidt wrote:
Joel de Guzman schrieb:
On 8/17/2010 5:10 AM, Christopher Schmidt wrote:
I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible. the example I used in a previous email would then outright fail until support for proxies is added, as opposed to work in one case and fail in another, very similar, case.
Those are very good points. I await for Christopher's reply. I think what you gave is a reasonable strategy. I like it.
I don't agree. The proxy is indeed clumsy, but due to being implicitly convertible to the underlying type it does its job quite well. In most use-cases an adapted 'class' does feel just like any other regular fusion container. In my opinion, fully exposing the proxy type is not conducive as the type of interest is always the type encapsulated by the wrapper. The proxy is just a means to an end. If the special traits of proxies are ditched, that is if the implicit conversion ability is removed and the proxy is exposed as the actual value type, all generic user code will need to handle proxy types explicitly. Generic user tmp code would probably need hacky mpl-code that distinguishes fusion proxies from non-proxy value types. Generic run-time functors would need to be specialized for proxies. That is prone to errors! With the current design, only very few run-time functors have to be specialized for proxies at all.
Also very good points. I think the proxy should behave similar to Boost ref, as it should expose an implicit conversion to T. This alone will satisfy many code that expects T. As for exposing the proxy as the value type of the sequence, you are right. However, what we can probably do is to be consistent with handling const and non-const and always return a proxy so there is no surprise when code works one way and not the other way.
I agree.
Stefan, considering your special use-case: if the proxy's underlying value type is exposed as the real value type of the sequence, you don't need to specialize your functor at all. See the attached code - ref_for_each is an implementation of fusion::for_each that internally resolves proxy types. Such an approach hides the proxy completely!
I do not see how fully exposing the proxy leads to simpler or less error prone code. Therefore I vote for keeping the interface as it is - with the proxy type being documented and its semantics fully exposed to the user. As for the name, I do like ADAPT_EXPR or ADAPT_ADT more than ADAPT_CLASS.
My problem with this approach is that you need special algorithms to deal with these proxies. It may not be a bad idea to embrace proxies (and reference wrappers) library wide as intrinsic to our concepts, so that proxies will be totally transparent, but I am not quite sure if it's worth it. It's an additional burden for algorithm writers to deal with.
Well, that is a *lot* of work - and such an approach does not hide the proxy completely. The return type of fusion::deref is still a proxy.
I think we should proxify the 'const' return type and rename BOOST_FUSION_ADAPT_xxxCLASSxxx to BOOST_FUSION_ADAPT_xxxADTxxx . BOOST_FUSION_ADAPT_xxxEXPRxxx breaks ranks as EXPR does not relate to the adaptee at all. boost::fusion::extension::class_member_proxy<T> should be changed to boost::fusion::extension::adt_attribute_proxy<T, B>, with B being a boolean constant that is true for lvalue and false for rvalue proxies. The drawbacks of proxies should be pointed out explicitly in the documentation, including a short abstract that advocates adapting abstract data types using fusion's native extension mechanism in order to avoid the proxy.
Are there any objections to these changes? Stefan, is this acceptable for you?
Sounds good to me. The name adt_attribute_proxy is a bit too long though. I'd prefer a shorter name but I can't think of one yet. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Joel de Guzman wrote:
Sounds good to me. The name adt_attribute_proxy is a bit too long though. I'd prefer a shorter name but I can't think of one yet.
Would "adt_property" work? It loses "proxy," but doesn't the proxy represent a property of the ADT in this case? _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

Christopher Schmidt schrieb:
Joel de Guzman schrieb:
On 8/17/2010 5:10 AM, Christopher Schmidt wrote:
I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible. the example I used in a previous email would then outright fail until support for proxies is added, as opposed to work in one case and fail in another, very similar, case.
Those are very good points. I await for Christopher's reply. I think what you gave is a reasonable strategy. I like it.
I don't agree. The proxy is indeed clumsy, but due to being implicitly convertible to the underlying type it does its job quite well. In most use-cases an adapted 'class' does feel just like any other regular fusion container. In my opinion, fully exposing the proxy type is not conducive as the type of interest is always the type encapsulated by the wrapper. The proxy is just a means to an end. If the special traits of proxies are ditched, that is if the implicit conversion ability is removed and the proxy is exposed as the actual value type, all generic user code will need to handle proxy types explicitly. Generic user tmp code would probably need hacky mpl-code that distinguishes fusion proxies from non-proxy value types. Generic run-time functors would need to be specialized for proxies. That is prone to errors! With the current design, only very few run-time functors have to be specialized for proxies at all.
Also very good points. I think the proxy should behave similar to Boost ref, as it should expose an implicit conversion to T. This alone will satisfy many code that expects T. As for exposing the proxy as the value type of the sequence, you are right. However, what we can probably do is to be consistent with handling const and non-const and always return a proxy so there is no surprise when code works one way and not the other way.
I agree.
Stefan, considering your special use-case: if the proxy's underlying value type is exposed as the real value type of the sequence, you don't need to specialize your functor at all. See the attached code - ref_for_each is an implementation of fusion::for_each that internally resolves proxy types. Such an approach hides the proxy completely!
I do not see how fully exposing the proxy leads to simpler or less error prone code. Therefore I vote for keeping the interface as it is - with the proxy type being documented and its semantics fully exposed to the user. As for the name, I do like ADAPT_EXPR or ADAPT_ADT more than ADAPT_CLASS.
My problem with this approach is that you need special algorithms to deal with these proxies. It may not be a bad idea to embrace proxies (and reference wrappers) library wide as intrinsic to our concepts, so that proxies will be totally transparent, but I am not quite sure if it's worth it. It's an additional burden for algorithm writers to deal with.
Well, that is a *lot* of work - and such an approach does not hide the proxy completely. The return type of fusion::deref is still a proxy.
I think we should proxify the 'const' return type and rename BOOST_FUSION_ADAPT_xxxCLASSxxx to BOOST_FUSION_ADAPT_xxxADTxxx . BOOST_FUSION_ADAPT_xxxEXPRxxx breaks ranks as EXPR does not relate to the adaptee at all. boost::fusion::extension::class_member_proxy<T> should be changed to boost::fusion::extension::adt_attribute_proxy<T, B>, with B being a boolean constant that is true for lvalue and false for rvalue proxies. The drawbacks of proxies should be pointed out explicitly in the documentation, including a short abstract that advocates adapting abstract data types using fusion's native extension mechanism in order to avoid the proxy.
I just committed a preliminary draft of the documentation of BOOST_FUSION_ADAPT_ADT to the trunk. The actual changes to the code were committed two weeks ago. The documentation can be found here: http://svn.boost.org/svn/boost/trunk/libs/fusion/doc/html/fusion/adapted/ada... http://svn.boost.org/svn/boost/trunk/libs/fusion/doc/html/fusion/notes.html#... https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/doc/adapted.qbk https://svn.boost.org/trac/boost/browser/trunk/libs/fusion/doc/notes.qbk Feel free to improve the wording in any way ;) I will have the documentation for the other macros (BOOST_FUSION_ADAPT_TPL_ADT, BOOST_FUSION_ADAPT_ASSOC_ADT, BOOST_FUSION_ADAPT_ASSOC_TPL_ADT) committed and merged by Saturday. The core code of the BOOST_FUSION_ADAPT_xxxADTxxx-macros is in https://svn.boost.org/trac/boost/browser/trunk/boost/fusion/adapted/adt/deta... This macro generates the necessary boilerplate, that are the proxy (fusion::extension::adt_attribute_proxy) specializations, the actual accessors (specializations of fusion::extension::access::adt_attribute_access) and the code necessary to reuse the underlying implementation of regular adapted structs. I added a get()-function to the proxy. This function may be used in case the implicit conversion is not feasible. The accessors and the proxy are disjointed so a user may just 'friend class fusion::extension::access' without having to deal with the proxy and its template arguments. For more information, see this post from Stefan. http://article.gmane.org/gmane.comp.lib.boost.devel/207247 Unfortunately this friending does not work with gcc 3.x as the access rights of a friend class are (incorrectly) not propagated to its nested classes. -Christopher

Zitat von Christopher Schmidt <mr.chr.schmidt@online.de>:
I think simply providing a sequence of proxies is less error-prone than trying to hide it when possible.
I don't agree. The proxy is indeed clumsy, but due to being implicitly convertible to the underlying type it does its job quite well. In most use-cases an adapted 'class' does feel just like any other regular fusion container.
our positions aren't really that far apart from each other: yours: for_each(s,f); //sometimes works ref_for_each(s,f); //always works mine: for_each(s,f); //never works for_each(s,deproxify(f)); //always works
In my opinion, fully exposing the proxy type is not conducive as the type of interest is always the type encapsulated by the wrapper. The proxy is just a means to an end. If the special traits of proxies are ditched, that is if the implicit conversion ability is removed and the proxy is exposed as the actual value type, all generic user code will need to handle proxy types explicitly. Generic user tmp code would probably need hacky mpl-code that distinguishes fusion proxies from non-proxy value types. Generic run-time functors would need to be specialized for proxies. That is prone to errors! With the current design, only very few run-time functors have to be specialized for proxies at all.
Stefan, considering your special use-case: if the proxy's underlying
is it that special? I wanted to show the const/non-const issue with it, so I guess it is, but doesn't even a simple transformation fail with proxies? template<typename T> T identity(T const &t){ return t; } fusion::transform(s,identity_obj); (with identity_obj being a generic function object that implements identity) basically any functor that doesn't force the proxy to implicitly convert the proxy to its value might not work as envisioned by the implementor of the functor (without having proxies in mind)

On 8/11/2010 6:46 PM, David Sankel wrote:
Up until this point, struct adaptation has exclusively been over the instance record, point c) above. This is very simple to understand and implies exactly one canonical adaptation for every struct/class.
This isn't exactly true. You can adapt a struct to multiple coexisting views by simply using BOOST_FUSION_ADAPT_STRUCT_NAMED ( or BOOST_FUSION_ADAPT_CLASS_NAMED ). -- ---------------------------------- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

Zitat von David Sankel <camior@gmail.com>:
I think the ADAPT_CLASS macros fundamentally change the expected behavior of struct adaptation in a negative way. A non-template class/struct is a collection of
a) types (declared as nested typedefs or other structs) b) values of the following variety i) static member variables (values that are non-functions) ii) static member functions (values that are functions) iii) member functions (values that are "special" functions over the instance record) c) an instance record, which includes member variables
Up until this point, struct adaptation has exclusively been over the instance record, point c) above. This is very simple to understand and implies exactly one canonical adaptation for every struct/class.
ADAPT_CLASS mixes point c) and point iii) in an arbitrary way.
although I wouldn't say ADAPT_CLASS should be removed as I don't know its use cases (supposedly it is used in Boost.Spirit?) I agree that there are significant differences between ADAPT_CLASS and _STRUCT that aren't clear from their names. for my use case (SYB) I have to document the rather confusing fact that _classes_ must be adapted with ADAPT_STRUCT, and while ADAPT_CLASS might seem to work at first, classes (or structs) must NOT be adapted using ADAPT_CLASS. the reason for that is that the "reference type" of ADAPT_CLASS sequences iterator is a proxy object, instead of a reference to the value. on 2 different notes, related to ADAPT_*: - although christopher understandably wasn't enthusiastic about adding new macros, we've agreed to a way to implement "derived" adapt macros. suggested interface: ADAPT_SUBCLASS/ADAPT_SUBSTRUCT, including all variants like NAMED, ASSOC, AS_VIEW - the ASSOC variants are documented to adapt an associative sequence. which they do according to the fusion concepts, but it does seem rather strange to me that the keys are not part of the value type of the sequence. for example: struct A{ int a; struct a_key; }; FUSION_ADAPT_ASSOC_STRUCT(A, (int,a,A::a_key)) void f(fusion::pair<A::a_key,int> p){ ... } fusion::for_each(A(),bind(f,_1)); error: the value type of the first element is "int", not a pair <a_key,int>. although this seems to be in perfect compliance with the Fusion associative sequence concept, is there any other associative sequence like that? fusion::map does have a fusion::pair<> value type. iterating a ADAPT_ASSOC_STRUCT sequence with its keys is a big hassle, probably using fusion::iter_fold and accessing the keys from the associative iterator. -Stefan
participants (8)
-
Christopher Schmidt
-
David Sankel
-
Hartmut Kaiser
-
Joel de Guzman
-
Lars Viklund
-
Michael Caisse
-
Stefan Strasser
-
Stewart, Robert