data_binding library for boost... Any interest?

I looked through boost and if there is a library or facility for data binding in boost I could not find it... So I created and am submitting a simple example for review. Please take a look and give some feedback. I understand that there is quiet a process of review before a library is included in boost. If there is interest or if there is already on going work on the concept than I am interested in helping. Here goes: Data binding should allow for 1 value of primitive type to be changed in code and have 1 to N values be modified based on the event and optional conversion functions. i.e. fanout should be allowed Data binding should allow for cascading changes. Where a->b->c->d where -> represents a binding link when 'a' changes 'c', 'b', and 'd' should change. Data binding should be recursion save where a->b->c->a where a change in 'a' causes a change in 'c', but will not cause a recursive change in 'a' creating a recursive loop. Data binding would be useful in the dataflow library and for work being done on cppgui or for that fact any UI development. This is my first submittal to this list so please bear with me. I have taken the liberty to add the boost license to this code... so it is boost's if the project so chooses to incorporate or enhance the concept. I am not the originator of data binding concept and make no claim to this. I am only providing a simple example for discussion and hopefull inclusion of data binding concept in boost and ....ultimately modify the C++ compiler to provide for a lighter weight solution (events based on modifications of integral types) - Ouch ... yes I know what I am asking here... see the last part of the example output for why I ask this. // Start snip bind_value.hpp ======================================= // // (C) Copyright Brian Davis. // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Revision history: // 19 July 2008 // Created - to support and assist in dataflow and dataflow concepts // // This is not currently part of boost! The only reason for the above copyright is to // keep these concepts part of the boost development. boost::data_binding is not // officially part of boost. The goal of this demo code is to elaborate on data binding // and give a simple implementation and an example on how the concept can be applied within C++. #ifndef BOOST_DATA_BINDING_HPP #include <boost/cast.hpp> #include <boost/function.hpp> #include <boost/bind.hpp> #include <boost/foreach.hpp> #include <vector> namespace boost { namespace data_binding { template < class T1, class T2> class bind_values; template <class T> class value { friend class bind_values< class T1, class T2>; public: typedef boost::function< T& (T&) > set_value_function; std::vector<set_value_function> set_value_functions; T& mv_value; // To prevent infinite recursion on a group of three linked variables a->b->c->a. bool mv_entered; protected: private: public: value( T& invalue ) : mv_value( invalue ){ mv_entered = false; }; // Sets require action event handling to update value of binded type.. gets are transparent value& operator=( T& rhs ) { if( set_value_functions.size() && !mv_entered ) { mv_entered = true; BOOST_FOREACH( set_value_function set_value, set_value_functions ) { mv_value = set_value( rhs ); } } else { // Otherwise simple type cast convert mv_value = boost::numeric_cast<T>( rhs ); } mv_entered = false; return *this; } value& operator=( T rhs ) { if( set_value_functions.size() && !mv_entered ) { mv_entered = true; BOOST_FOREACH( set_value_function set_value, set_value_functions ) { mv_value = set_value( rhs ); } } else { // Otherwise simple type cast convert mv_value = boost::numeric_cast<T>( rhs ); } mv_entered = false; return *this; } void add_set_function( set_value_function set_function ) { set_value_functions.push_back( set_function ); } T& operator&( value<T>& value ) { return value.mv_value; } protected: private: }; template < class T1, class T2> class bind_values { friend class value<T1>; friend class value<T2>; public: typedef T1 type1; typedef T2 type2; typedef boost::function< T1& (T1, T2)> convert_to_function; typedef boost::function< T2& (T2, T1)> convert_from_function; convert_to_function convert_to; convert_from_function convert_from; protected: value<T1>& mv_value1; value<T2>& mv_value2; private: public: bind_values ( value<T1>& value1, value<T2>& value2, convert_to_function convertTo, convert_from_function convertFrom ) : convert_to(convertTo), convert_from(convertFrom), mv_value1( value1 ), mv_value2( value2 ) { // Hook up set for value 1 mv_value1.add_set_function( boost::bind( &bind_values::set_value1, this, _1 ) ); // Hook up set for value 2 mv_value2.add_set_function( boost::bind( &bind_values::set_value2, this, _1 ) ); } bind_values( value<T1>& value1, value<T2>& value2 ) : mv_value1( value1 ), mv_value2( value2 ) { // Hook up set for value 1 mv_value1.set_value = boost::bind( &bind_values::set_value1, _1 ); // Hook up set for value 2 mv_value2.set_value = boost::bind( &bind_values::set_value2, _1 ); } protected: T1& set_value1( T1& value ) { if( convert_from ) { // Convert and set value 2 mv_value2 = boost::numeric_cast<T2>( convert_from( mv_value2.mv_value, value ) ); } else { // Otherwise simple type cast convert mv_value2 = boost::numeric_cast<T2>( value ); } // return the value unmodified to the original container return value; } T2& set_value2( T2& value ) { if( convert_to ) { // Convert and set value 1 mv_value1 = boost::numeric_cast<T1>( convert_to( mv_value1.mv_value, value ) ); } else { // Otherwise simple type cast convert mv_value1 = boost::numeric_cast<T1>( value ); } // return the value unmodified to the original container return value; } private: }; } } // namespace boost::data_binding template <class T> std::ostream& operator<<( std::ostream& os, boost::data_binding::value<T>& rhs ) { os << rhs.mv_value;; return os; } #endif // end snip bind_value.hpp ======================================= // Start snip bind_value_test.hpp ======================================= // // (C) Copyright Brian Davis. // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Revision history: // 19 July 2008 // Created - to support and assist in dataflow and dataflow concepts // // This is not currently part of boost! The only reason for the above copyright is to // keep these concepts part of the boost development. boost::data_binding is not // officially part of boost. The goal of this demo code is to elaborate on data binding // and give a simple implementation and an example on how the concept can be applied within C++. #include <iostream> #include <boost/cstdint.hpp> #include <boost/bind.hpp> #include <boost/data_binding/bind_value.hpp> #define MAX_CELSIUS 100 #define MIN_CELSIUS -17.8 #define MAX_RAW_SENSOR_COUNTS 4095 // use of a class is not necessary it is only shown to prove it is possible. It may // make more sense just to have conversion functions class AClass_That_Is_A_Converter { public: protected: boost::data_binding::value<boost::uint32_t> rawCelsiusCountsFromSensor; boost::data_binding::value<float> calibratedCelsiusDataFromSensor; boost::data_binding::value<float> calibratedFahrenheit; boost::uint32_t rawSensorValue; float fahrenheit; float celsius; boost::data_binding::bind_values<float, boost::uint32_t> mv_celsiusToSensorBinder; boost::data_binding::bind_values<float, float> mv_celsiusToFahrenheitBinder; private: public: AClass_That_Is_A_Converter( void ) : rawCelsiusCountsFromSensor(rawSensorValue), calibratedCelsiusDataFromSensor(celsius), calibratedFahrenheit(fahrenheit), mv_celsiusToSensorBinder ( calibratedCelsiusDataFromSensor, rawCelsiusCountsFromSensor, boost::bind( &AClass_That_Is_A_Converter::convertCelsiusRawToCalibrated, this, _1, _2 ), boost::bind( &AClass_That_Is_A_Converter::convertCelsiusCalibratedToRaw, this, _1, _2 ) ), mv_celsiusToFahrenheitBinder ( calibratedCelsiusDataFromSensor, calibratedFahrenheit, boost::bind( &AClass_That_Is_A_Converter::convertFahrenheitToCelsius, this, _1, _2 ), boost::bind( &AClass_That_Is_A_Converter::convertCelsiusToFahrenheit, this, _1, _2 ) ) {} virtual ~AClass_That_Is_A_Converter( void ){} void test( void ) { std::cout << "Starting test of data binding" << std::endl; try { std::cout<< "Note raw temp represents the raw value of an Analog to Digital Converter" << std::endl; std::cout<< "The range is from 0-4095 which represents -17.8 - 100 degrees on the Celsius" << std::endl; std::cout<< "scale and 0 - 212 degrees on the Fahrenheit" << std::endl; std::cout<< "Setting calibratedFahrenheit to 70.0 degrees fahrenheit" << std::endl; std::cout<< "calibratedFahrenheit = 70.0f;" << std::endl; calibratedFahrenheit = 70.0f; std::cout << "What does the celsius value contain? ... should be ~21.1" << std::endl; showValues(); std::cout << "Now change the raw sensor value and see what happens to Celsius and Fahrenheit" << std::endl; std::cout<< "rawCelsiusCountsFromSensor = 4095;" << std::endl; rawCelsiusCountsFromSensor = 4095; std::cout << "Celsius should equal ~100" << std::endl; std::cout << "Fahrenheit should equal ~212" << std::endl; showValues(); std::cout << "Now change celsius see what happens to raw and farenheit" << std::endl; std::cout<< "calibratedCelsiusDataFromSensor = 32.2;" << std::endl; calibratedCelsiusDataFromSensor = 32.2; std::cout << "Fahrenheit should equal ~90 degress" << std::endl; showValues(); std::cout << "Note changing original values will not have any affect in C++ " << std::endl; std::cout << "this makes me sad :-( as a class wrapper and operator overloading" << std::endl; std::cout << "is necessary... without changing the compiler... hint.... hint..." << std::endl; std::cout << "fahrenheit = 10;" << std::endl; fahrenheit = 10; showValues(); std::cout << "No change in values :-( !!!" << std::endl; // Note one to many fanout is possible and the example shows 1 to 2 fanout with Celsius // fanning out to Raw and Fahrenheit values. A more advanced implementation is also possible // which includes the use of the lamda library and place holders. This is just a simple // example which I hope will "prime the pump" for work on a data_binding library with in // the Boost development. Most direct use for this library is within data_flow library. // Another use is within the cppgui library which would allow modification of data to directly // affect values of UI controls and display values. } catch( std::exception& ex ) { std::cout << "Failed with exception: " << ex.what(); } std::cout << "End of data binding test" << std::endl; } void showValues( void ) { std::cout << std::endl; std::cout << "Fahrenheit : " << calibratedFahrenheit << std::endl; std::cout << "Celsius : " << calibratedCelsiusDataFromSensor << std::endl; std::cout << "Raw Temp To/From Sensor A/D converter : " << rawCelsiusCountsFromSensor << std::endl; std::cout << std::endl; std::cout << "fahrenheit : " << fahrenheit << std::endl; std::cout << "celsius : " << celsius << std::endl; std::cout << "rawSensorValue : " << rawSensorValue << std::endl; std::cout << std::endl; std::cout << "====================================================================" << std::endl; } protected: float& convertFahrenheitToCelsius ( float& celsius , float& fahrenheit ) { return celsius = ((fahrenheit - 32.0) * 5.0) / 9.0; } float& convertCelsiusToFahrenheit ( float& fahrenheit, float& celsius ) { return fahrenheit = celsius * (9.0 / 5.0) + 32.0; } float& convertCelsiusRawToCalibrated ( float& calibratedValue, boost::uint32_t& rawValue ) { return calibratedValue = ( MAX_CELSIUS - MIN_CELSIUS ) * (rawValue / MAX_RAW_SENSOR_COUNTS) + MIN_CELSIUS; } boost::uint32_t& convertCelsiusCalibratedToRaw ( boost::uint32_t& rawValue, float& calibratedValue ) { // Raw is from 0 to 4095 ( a 12 bit number of an // Analog to Digital converter // map zero (fahrenheit) to water boiling to raw value of 4095 return rawValue = MAX_RAW_SENSOR_COUNTS * ( calibratedValue - MIN_CELSIUS) / ( MAX_CELSIUS - MIN_CELSIUS ); } private: }; int main(int argc, char **argv) { AClass_That_Is_A_Converter anExampleOfDataBinding; anExampleOfDataBinding.test(); } // end snip bind_value_test.hpp ======================================= // Start snip program output ======================================= Starting test of data binding Note raw temp represents the raw value of an Analog to Digital Converter The range is from 0-4095 which represents -17.8 - 100 degrees on the Celsius scale and 0 - 212 degrees on the Fahrenheit Setting calibratedFahrenheit to 70.0 degrees fahrenheit calibratedFahrenheit = 70.0f; What does the celsius value contain? ... should be ~21.1 Fahrenheit : 70 Celsius : 21.1111 Raw Temp To/From Sensor A/D converter : 1352 fahrenheit : 70 celsius : 21.1111 rawSensorValue : 1352 ==================================================================== Now change the raw sensor value and see what happens to Celsius and Fahrenheit rawCelsiusCountsFromSensor = 4095; Celsius should equal ~100 Fahrenheit should equal ~212 Fahrenheit : 212 Celsius : 100 Raw Temp To/From Sensor A/D converter : 4095 fahrenheit : 212 celsius : 100 rawSensorValue : 4095 ==================================================================== Now change celsius see what happens to raw and farenheit calibratedCelsiusDataFromSensor = 32.2; Fahrenheit should equal ~90 degress Fahrenheit : 89.96 Celsius : 32.2 Raw Temp To/From Sensor A/D converter : 1738 fahrenheit : 89.96 celsius : 32.2 rawSensorValue : 1738 ==================================================================== Note changing original values will not have any affect in C++ this makes me sad :-( as a class wrapper and operator overloading is necessary... without changing the compiler... hint.... hint... fahrenheit = 10; Fahrenheit : 10 Celsius : 32.2 Raw Temp To/From Sensor A/D converter : 1738 fahrenheit : 10 celsius : 32.2 rawSensorValue : 1738 ==================================================================== No change in values :-( !!! End of data binding test // End snip program output ======================================= This was done to assist Sjepan Rajko in his work on the dataflow library (he beat me to it :-) ). Dataflow provides the event model data_binding provides the means to do data conversion between events. Brian.

On Sun, Jul 20, 2008 at 9:37 PM, Brian Davis <bitminer@gmail.com> wrote:
I looked through boost and if there is a library or facility for data binding in boost I could not find it... So I created and am submitting a simple example for review.
[snip]
Dataflow provides the event model data_binding provides the means to do data conversion between events.
Hi Brian, You are right in that this combines two problems - one is binding values together (the part that is very appropriate for Dataflow), and the other is transformations of values (which is useful in itself). Even though these could be left as orthogonal concepts, perhaps gluing these two together might also be interesting. I have tried to tackle the value/domain transformation problem a while back, inspired by Brook Milligan's (CC-d) probability library (which can nicely transition probability values between linear and log domains). My attempt at a generic domain-transformation solution relied on a "pivot" type. That is, you could transition from any domain to any other domain as long as both specified how to transition to some common, "pivot" type. This is where it is different from your solution, where you specify pairwise transformations (I think in my implementation you could also specify direct transforms, but I don't remember). E.g., here is how you implement a log domain: http://pastebin.com/f6dd9c7d ... and some test code: http://pastebin.com/f160d91e9 I think you can download the whole thing packaged with other stuff at: http://ame4.hc.asu.edu/amelia/download/ Brook Milligan also worked on a generic domain transformation library, so he might comment on this as well. There is also the Boost.Units library which might offer transformations for some cases. Going back to dataflow+transformations... If the two were left separate, we could implement the binding (no transformations) part easily as a part of the Dataflow library. That would mean you can only bind together values of the same type/domain. I think it basically reduces to a shared_ptr if you don't care about getting notified about a change. On top of that, then, when you need bound values to exist in different domains (e.g., Celsius, Farenheit, sensor), each value can do it's own transformation to/from the shared value (think star topology). This is similar to the "pivot" type concept. Now, there are times when this would not be desirable. One case is when the transformations to the pivot type lose precision, so you'd rather connect the bound values in a ring of some sort (or some other connected component in graph terms), and each connection would have transformations (one for each direction) built into it. Once a value gets changed, the network would need to decide on which (one) path to use to update each other value. Also, I think there are some interesting lazy evaluation possibilities (don't calculate the transforms until needed). Anyway, I think it would be interesting to try to add some of this to the dataflow library. Would you prefer the "star topology" solution, or the other one (similar to yours) with arbitrary connection/transformation topologies? (first can be seen as a special case of the second, but maybe has a simpler implementation)? Stjepan

Stjepan Rajko writes:
I have tried to tackle the value/domain transformation problem a while back, inspired by Brook Milligan's (CC-d) probability library (which can nicely transition probability values between linear and log domains).
Brook Milligan also worked on a generic domain transformation library, so he might comment on this as well. There is also the Boost.Units library which might offer transformations for some cases.
Thanks, Stjepan. I've continued to refactor that, actually, to make it support the more generic problem under discussion here. So far it is mostly done. I think the only issues are some silly overloading resolution issues that have little to do with the basic ideas. For the discussion I'll outline my approach. The basic observation that motivates this is that in some (many?) situations there exist a group of related types that clearly have common semantics in the application domain but may impose different constraints in their implementation. Indeed, some operations may not be practical or feasible for some of the types but could be for others and there may exist transformations from one to another. In the case of probabilities think of two types, one for a probability and one for its logarithm with appropriate operators defined for each domain and the interconversions. Another example involves the representation of polynomials, which can be in terms of coefficients or in spectral terms that ease their multiplication. In this case, it may be completely undesirable to implement a polynomical multiplication for the coefficient representation. Conceptually then, the Domain library seeks to create a framework for implementing sets of such types that work smoothly together, and enable the compiler to make choices about how to handle mixed domain operations (e.g., adding a probability and a log probability) or operations that must be performed in another domain (e.g., multiplying two polynomials represented as coefficients). I think these are most of the salient points, all of which are currently supported. - Allow definition of families of types (domains) based upon each member of a family sharing common semantics in the application domain. - Allow implementation (or not) of any within-domain operators that make sense in the application domain. - Allow implementation (or not) of any appropriate interdomain type transformations. - Decouple the domain type information from the value types used to represent the internal domain-specific information. - Allow specification of a default value type for any domain type so that unspecified templates (i.e., T<>) provide meaningful results. - Allow specification of which domains are interconvertible as a series of pairwise conversions. - Allow specification of which domains support which operations so that the compiler can seek an appropriate domain for arguments that may (or may not) be directly usable. The goal is to clearly define all these points of extension so that the "real" types (e.g., probabilities or polynomials) can be constructed on top of the Domain library, thereby simplifying the specification of domain families for any application or library. I have been using this to refactor the Probability library as a proof of concept. As mentioned, most of what the old version could do, the new one will also do. There are a few issues with overloads that are confusing to me, so help is welcome. Thus, I am certain that there is some merit in this approach to a generic domain solution. However, I am also certain that there are other ideas out there that could improve this. Because of the interaction in development between the two libraries (Domain and Probability) I haven't quite finished everything. I'll try to roll them up for viewing shortly, though. In the meantime, if anyone can help me set up the appropriate bjam magic for getting quickbook documentation built, including incorporating doxygen generated information, I'll even improve the organization for plugging directly into Boost. I look forward to continuing discussion, receiving input, and discovering how these ideas might be put to use in other contexts. Cheers, Brook

On 07/22/08 15:07, Brook Milligan wrote:
Stjepan Rajko writes:
I have tried to tackle the value/domain transformation problem a while back, inspired by Brook Milligan's (CC-d) probability library (which can nicely transition probability values between linear and log domains).
Brook Milligan also worked on a generic domain transformation library, so he might comment on this as well. There is also the Boost.Units library which might offer transformations for some cases.
Thanks, Stjepan. I've continued to refactor that, actually, to make it support the more generic problem under discussion here. So far it is mostly done. I think the only issues are some silly overloading resolution issues that have little to do with the basic ideas. For the discussion I'll outline my approach.
The basic observation that motivates this is that in some (many?) situations there exist a group of related types that clearly have common semantics in the application domain but may impose different constraints in their implementation. Indeed, some operations may not be practical or feasible for some of the types but could be for others and there may exist transformations from one to another. In the case of probabilities think of two types, one for a probability and one for its logarithm with appropriate operators defined for each domain and the interconversions. Another example involves the representation of polynomials, which can be in terms of coefficients or in spectral terms that ease their multiplication. In this case, it may be completely undesirable to implement a polynomical multiplication for the coefficient representation.
Conceptually then, the Domain library seeks to create a framework for implementing sets of such types that work smoothly together, and enable the compiler to make choices about how to handle mixed domain operations (e.g., adding a probability and a log probability) or operations that must be performed in another domain (e.g., multiplying two polynomials represented as coefficients). I think these are most of the salient points, all of which are currently supported.
- Allow definition of families of types (domains) based upon each member of a family sharing common semantics in the application domain.
- Allow implementation (or not) of any within-domain operators that make sense in the application domain.
- Allow implementation (or not) of any appropriate interdomain type transformations.
- Decouple the domain type information from the value types used to represent the internal domain-specific information.
- Allow specification of a default value type for any domain type so that unspecified templates (i.e., T<>) provide meaningful results.
- Allow specification of which domains are interconvertible as a series of pairwise conversions.
- Allow specification of which domains support which operations so that the compiler can seek an appropriate domain for arguments that may (or may not) be directly usable.
[snip] In this thread, there's frequent mention of domains, and groups of related types and transformations between domains. Thes phrases remind me of proto's transformations: http://boost-sandbox.sourceforge.net/libs/proto/doc/html/boost_proto/users_g... is there any chance proto could be used? Also, the mention of common set of types and transformations reminds me of algebras and transformations between those algebras. In particular, there was mention of some operators defined for some domains and not for others. This reminds me of algebraic structure that have a limited set of operators. For example: http://planetmath.org/encyclopedia/Monoid.html http://planetmath.org/encyclopedia/Ring.html and more generally, for any number of operators: http://planetmath.org/encyclopedia/HomomorphismBetweenAlgebraicSystems.html The 'group of related types' phrase reminds me of 'many-sorted algebras' where each sort corresponds to type in 'group of related types': http://planetmath.org/encyclopedia/ManySortedStructure.html Is there any chance the data_binding library is related? IOW, would the data_binding library dos use some of the terminology in the above planetmath .htmls to describe the library's purpose?

Larry Evans writes:
In this thread, there's frequent mention of domains, and groups of related types and transformations between domains. Thes phrases remind me of proto's transformations:
http://boost-sandbox.sourceforge.net/libs/proto/doc/html/boost_proto/users_g...
is there any chance proto could be used?
Yes, there probably is. As you probably guessed, I'm using MPL stuff to do some of the type deduction. I'm not certain that I'm up for Proto just yet, but that may be a promising path to consider. Currently, I'm thinking that would end up being an implementation detail so some of the issues could be worked out first and then perhaps improved upon by using Proto. Thoughts?
Also, the mention of common set of types and transformations reminds me of algebras and transformations between those algebras.
Yes, it would seem to have a lot of similarities. Indeed, qualitatively I have some of the same thoughts. However, I have not mapped my ideas into that formal mathematical domain very carefully, yet. I agree completely that if there is a good mapping, I should be using that language for at least one level of the discussion. At the same time, that language, while precise, is pretty abstract. Thus, I have opted to start with more practical descriptions. I'll give this more careful thought, though. Thanks. Cheers, Brook

[snip] In this thread, there's frequent mention of domains, and groups of related types and transformations between domains. Thes phrases remind me of proto's transformations:
http://boost-sandbox.sourceforge.net/libs/proto/doc/html/boost_proto/users_g...
is there any chance proto could be used?
Yes it appears proto with the syntax of (_1 + 3) (_2 - _1) / _2 * 100 could be used. This format seemingly provides a simple syntax for the programmer. My example only called pairwise non MPL transformation functions which the programmer can specify... there is some merit to non MPL syntax in keeping the code simple and the transformation simple to specify. So another issue is runtime / compile time specification of transforms. Can transforms be specified at runtime? With my example they can as the transform functions are simply boost::function calls. Can the syntax (_2 - _1) / _2 * 100 ) also call user defined functions such as ( _2 -1) / _2 *100 / g(_1, _2 ) ) Can the syntax be used to specify arbitrary function transforms defined by the programmer? Does it allow to bind two or more values together where one is changed and the remaining values are affected through overloading the operator= and calling specified transform functions. If yes then yes this is what I am after. I think there are two issues here transforms and how they are specified and databinding where multiple values are bound to each other... change 1 and they all change automatically (binding). Transformations specify how the bound values get transformed. The key I desire is to specify the transforms upfront and then simply change the value in code knowing that the transformation functions will yield a result on the remaining data bound variables based on the specified transform(s). Excerpt from proto: "The transform above might look a little strange at first. It appears to be constructing a temporary object in place. In fact, it is a *function type*. Since terminal<long>::type and _arg are types, terminal<long>::type(_arg) is actually the type of a function that takes _arg as a parameter and returns terminal<long>::type. That is immaterial; there is no such function in reality. Rather, Proto interprets this function type as a transform, the effect of which is described above. The resemblance to an in-place construction of a temporary object is intentional. It is a concise and natural notation for specifying transforms. Proto transforms use function types extensively, as we'll see. " and "When using function types as Proto transforms, they can either represent an object to construct or a function to call. It is similar to C++ where the syntax foo(x) can either be interpreted as an object to construct or a function to call, depending on whether foo is a type or a function. " so my above example ( _2 -1) / _2 *100 / g(_1, _2 ) ) would not work. Which is fine... I do not have an answer for this either unless g(_1,_2) also created an mpl object correct? I don't see here where operator= is overloaded which will automatically call specified transforms. It is not to say Proto could not be made to work or it does work and just requires more thought on my part. With Proto transforms Excerpt from proto int i = 0; // not used, dummy state and visitor parameter std::cout << CalcArity()( lit(100) * 200, i, i) << '\n'; std::cout << CalcArity()( (_1 - _1) / _1 * 100, i, i) << '\n'; std::cout << CalcArity()( (_2 - _1) / _2 * 100, i, i) << '\n'; Calculates how many arguments are operated on 0 for the first as they are constants, 1 for the second as only _1 is specified, and 2 for the third because both _1 and _2 are specified. What I desire is: int i =0, j =0; bind_values<int, int>( ( _1 = 2 * _2, _2 = 1 / 2 *_1,i, j ); // my example does not support this syntax which proto does i = 2; std::cout << j << std::endl; // produces 4 j = 16; std::cout << i << std::endl; // produces 8
Also, the mention of common set of types and transformations reminds me of algebras and transformations between those algebras. In particular, there was mention of some operators defined for some domains and not for others. This reminds me of algebraic structure that have a limited set of operators. For example:
http://planetmath.org/encyclopedia/Monoid.html http://planetmath.org/encyclopedia/Ring.html
and more generally, for any number of operators:
http://planetmath.org/encyclopedia/HomomorphismBetweenAlgebraicSystems.html
The 'group of related types' phrase reminds me of 'many-sorted algebras' where each sort corresponds to type in 'group of related types':
http://planetmath.org/encyclopedia/ManySortedStructure.html
Is there any chance the data_binding library is related? IOW, would the data_binding library dos use some of the terminology in the above planetmath .htmls to describe the library's purpose?
My data binding does example, and I stress here simple, does not support domain transformation, but it sounds like Brook's transformation library does. Brian

AMDG Brian Davis wrote:
I am only providing a simple example for discussion and hopefull inclusion of data binding concept in boost and ....ultimately modify the C++ compiler to provide for a lighter weight solution (events based on modifications of integral types) - Ouch ... yes I know what I am asking here... see the last part of the example output for why I ask this.
What exactly do you mean by a lighter weight solution? Allowing events to be registered for an arbitrary int would have the following consequences: The compiler would have to insert extra code for every integer assignment, severely degrading performance regardless of whether this feature is used--except where the compiler can prove that no event is registered for a particular integer. The function f(int& i) { i = 0; } could throw. This would break a lot of exception safety guarantees. Every assignment could modify any variable, effectively forbidding many compiler optimizations based on pointer alias analysis. In Christ, Steven Watanabe

--except where the compiler can prove that no event is registered for a particular integer.
Yes... Exactly. Either you pay for the overhead of the template type or you pay in the compiler adding extra code for types where events can be registered. . The difference is that it provides for direct data binding for primitive types. Syntax can make it clear to the compiler that extra code must be inserted. In your example there is no syntax that specifies a get/set for the local variable i. The problem I think is clear the solution... not so much. Brian

AMDG Brian Davis wrote:
--except where the compiler can prove that no event is registered for a particular integer.
Yes... Exactly. Either you pay for the overhead of the template type or you pay in the compiler adding extra code for types where events can be registered. . The difference is that it provides for direct data binding for primitive types. Syntax can make it clear to the compiler that extra code must be inserted. In your example there is no syntax that specifies a get/set for the local variable i. The problem I think is clear the solution... not so much.
Ok. That's better. One more issue: Callbacks should be unregistered when the object that they are associated with are destroyed, right? How do you propose to handle this for POD? In Christ, Steven Watanabe

Callbacks should be unregistered when the object that they are associated with are destroyed, right?
Yes absolutely
How do you propose to handle this for POD?
POD out of scope Bidirectional Databinding function pointer destruction? The real trick is that in my example POD could be chained together so upon destruction the chain must be traversed or a list kept of all bound variables which is used to unregister the remaining data bound PODs. It's not clear to me how to handle this. I don't have all the answers... hopefully these discussions would help flush them out. Step 1: Ask the question: Does this concept have merit? Step 2: Investigate the possibilities Step 3 Propose solutions Not sure I even know the answer to step 1 yet. I know it makes for cleaner code.. This helps. I posted my example to see if there was any interest and see if it has merit. Brian. On Thu, Jul 24, 2008 at 9:26 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
Brian Davis wrote:
--except where the compiler can
prove that no event is registered for a particular integer.
Yes... Exactly. Either you pay for the overhead of the template type or you pay in the compiler adding extra code for types where events can be registered. . The difference is that it provides for direct data binding for primitive types. Syntax can make it clear to the compiler that extra code must be inserted. In your example there is no syntax that specifies a get/set for the local variable i. The problem I think is clear the solution... not so much.
Ok. That's better. One more issue:
Callbacks should be unregistered when the object that they are associated with are destroyed, right? How do you propose to handle this for POD?
In Christ, Steven Watanabe
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (5)
-
Brian Davis
-
brook@biology.nmsu.edu
-
Larry Evans
-
Steven Watanabe
-
Stjepan Rajko