[fusion] value_at of transform_view

Hi, I'm trying to fix ticket #1396: http://svn.boost.org/trac/boost/ticket/1396 The problem is that `result_of<identity(int)>::type` is triggered, where `int` is the result of `value_at` invocation into `vector<int, int>`. Now, I don't know what value_at of transform_view should return. In fact, I don't know even what value_at means. value_at semantics says "Returns the actual type at a given index from the Sequence." What is "the acutal type" of transform_view? (BTW, STL iterators don't have something like value_at.) Any hint? Regards, -- Shunsuke Sogame

shunsuke wrote:
Hi,
I'm trying to fix ticket #1396: http://svn.boost.org/trac/boost/ticket/1396 The problem is that `result_of<identity(int)>::type` is triggered, where `int` is the result of `value_at` invocation into `vector<int, int>`.
Now, I don't know what value_at of transform_view should return. In fact, I don't know even what value_at means. value_at semantics says "Returns the actual type at a given index from the Sequence." What is "the acutal type" of transform_view? (BTW, STL iterators don't have something like value_at.) Any hint?
I just replied to that in the ticket :-) HTH. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
shunsuke wrote:
Hi,
I'm trying to fix ticket #1396: http://svn.boost.org/trac/boost/ticket/1396 Any hint?
I just replied to that in the ticket :-) HTH.
Hmm, your `identity` implementation seems wrong. `result<Fun(int)>` invocation means that the argument is rvalue by the definition of result_of behavior. Therefore, you can't return mutable reference to `int`. -- Shunsuke Sogame

shunsuke wrote:
Joel de Guzman wrote:
shunsuke wrote:
Hi,
I'm trying to fix ticket #1396: http://svn.boost.org/trac/boost/ticket/1396 Any hint? I just replied to that in the ticket :-) HTH.
Hmm, your `identity` implementation seems wrong. `result<Fun(int)>` invocation means that the argument is rvalue by the definition of result_of behavior. Therefore, you can't return mutable reference to `int`.
Well, it's just for that specific case. Did you intend the transform to be generic? I didn't think so when you had it hard coded to int. I guess, it really depends on what your intent is. A transform cannot, in general, return a reference. What if the input is computed on the fly, like, say: mpl::vector_c<int, 1, 2, 3> ? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
shunsuke wrote:
Joel de Guzman wrote:
shunsuke wrote:
Hi,
I'm trying to fix ticket #1396: http://svn.boost.org/trac/boost/ticket/1396 Any hint? I just replied to that in the ticket :-) HTH. Hmm, your `identity` implementation seems wrong. `result<Fun(int)>` invocation means that the argument is rvalue by the definition of result_of behavior. Therefore, you can't return mutable reference to `int`.
Well, it's just for that specific case. Did you intend the transform to be generic? I didn't think so when you had it hard coded to int. I guess, it really depends on what your intent is. A transform cannot, in general, return a reference. What if the input is computed on the fly, like, say:
mpl::vector_c<int, 1, 2, 3>
Here's a more generic identity transform that works for mpl sequences too, FWIW (attached test in the trac ticket): struct identity { template<class FunCall> struct result; template <class Fun, class T> struct result<Fun(T)> { typedef T type; }; template <class T> T& operator()(T& val) const { return val; } template <class T> T const& operator()(T const& val) const { return val; } }; Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Well, it's just for that specific case. Did you intend the transform to be generic? I didn't think so when you had it hard coded to int. I guess, it really depends on what your intent is. A transform cannot, in general, return a reference. What if the input is computed on the fly, like, say:
mpl::vector_c<int, 1, 2, 3>
?
Yes, a FunctionObject return type is often orthogonal to deref type of sequence. In such case, a higher-order function is needed to avoid dangling: make_function_returning_value(identity_returning_reference()) Well, my question is more primitive: What is "value_at"? The current implementation is: value_at of transform_view returns boost::result_of<F(value_at of its underlying sequence)>::type I couldn't understand what this implementation wants to do. I tend to think `value_at` of transform_view should be the same as `result_of::deref` of transform_view. I'm not sure, though. Regards, -- Shunsuke Sogame

shunsuke wrote:
I tend to think `value_at` of transform_view should be the same as `result_of::deref` of transform_view. I'm not sure, though.
value_at (as well as value_of) returns (essentially): f(value_at<s>) while at (as well as deref) returns (essentially): f(at<s>) alas, this uncovers a bug in the implementation where value_at does not follow above. You got me thinking though. It could very well be that you are correct! Perhaps we need the same behavior for both at/deref and value_at/value_of. My thinking, OTOH, is that both should get the value_at of the underlying sequence. Hence, transform(vector<int, int&>, f) will trigger f this way: int ---> f::result<f(int)> int& ---> f::result<f(int&)> do you see a reason why it should be the other way around? Thanks to your keen sense! Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
shunsuke wrote:
I tend to think `value_at` of transform_view should be the same as `result_of::deref` of transform_view. I'm not sure, though.
value_at (as well as value_of) returns (essentially):
f(value_at<s>)
while at (as well as deref) returns (essentially):
f(at<s>)
alas, this uncovers a bug in the implementation where value_at does not follow above.
What is a bug? Is there any pitfall if `value_at` is the same as `at` under transform_view?
You got me thinking though. It could very well be that you are correct! Perhaps we need the same behavior for both at/deref and value_at/value_of. My thinking, OTOH, is that both should get the value_at of the underlying sequence. Hence, transform(vector<int, int&>, f) will trigger f this way:
int ---> f::result<f(int)> int& ---> f::result<f(int&)>
No, when vector<int, int&> is mutable lvalue, f should be able to access the mutable int. Hence, int --> f::result<f(int&)> int& --> f::result<f(int&)> The current deref works like this unless as_vector is used. It's ok. Again, #include <boost/fusion/include/as_vector.hpp> #include <boost/fusion/include/transform_view.hpp> #include <boost/fusion/include/vector.hpp> #include <boost/fusion/include/at.hpp> #include <boost/fusion/include/begin.hpp> struct identity { template<class FunCall> struct result; template<class Fun> struct result<Fun(int&)> { typedef int& type; }; int& operator()(int& i) const { return i; } }; void test() { // This compiles fine. typedef boost::fusion::vector<int, int> from_t; from_t from(10, 20); boost::fusion::transform_view<from_t, ::identity> v(from, ::identity()); *boost::fusion::begin(v) = 999; BOOST_CHECK(boost::fusion::at_c<0>(from) == 999); //boost::fusion::as_vector(v); // error! } Here, as_vector calls value_of. Hence, int --> f::result<f(int)> My poor identity doesn't compile. IMHO, as_vector should be able to return vector<int&, int&>. Once as_vector intervenes, FunctionObject can't access mutable elements in a tuple. For example, mutable STL iterator can't be returned from std::string in a tuple. Regards, -- Shunsuke Sogame

shunsuke wrote:
Joel de Guzman wrote:
alas, this uncovers a bug in the implementation where value_at does not follow above.
What is a bug?
See diff of the source in value_at_impl.hpp for the last 2 revisions.
Is there any pitfall if `value_at` is the same as `at` under transform_view?
After some more thinking, yes.
You got me thinking though. It could very well be that you are correct! Perhaps we need the same behavior for both at/deref and value_at/value_of. My thinking, OTOH, is that both should get the value_at of the underlying sequence. Hence, transform(vector<int, int&>, f) will trigger f this way:
int ---> f::result<f(int)> int& ---> f::result<f(int&)>
No, when vector<int, int&> is mutable lvalue, f should be able to access the mutable int. Hence,
int --> f::result<f(int&)> int& --> f::result<f(int&)>
I think you are missing the point. It is always mutable with deref and at. value_at and value_of should allow you to get the *actual* type of the underlying sequence. Think of value_at and value_of as having copy semantics.
The current deref works like this unless as_vector is used. It's ok.
That is because as_vector needs to know the actual type of the underlying sequence, hence it uses value_at/value_of. as_vector *copies* the source sequence.
Again,
[snip]
Here, as_vector calls value_of. Hence,
int --> f::result<f(int)>
My poor identity doesn't compile. IMHO, as_vector should be able to return vector<int&, int&>.
Once as_vector intervenes, FunctionObject can't access mutable elements in a tuple. For example, mutable STL iterator can't be returned from std::string in a tuple.
After some thinking, I am now convinced that the current behavior is still the proper way to do it. I added an attachment in the trac ticket that provides the correct way to do the identity transform. Mutability is not lost; never was. In the case of as_vector, a copy is generated, not a reference to the original. This copy has the *exact* same element types of the source sequence. If value_at were to do as at, then there is no way to do as_vector correctly if the source vector has a reference element. Here's a synopsis of what's being returned by at/deref and value_at/value_of given a vector<int, int&>: index element type at/deref value_at/value_of 0 T T& T 1 T& T& T& Notice that value_at/value_of always returns the exact type of the element. We should not deviate from that behavior. When a transform is used, it should do the same. Here's what's happening (given F as the transform function): index element type at/deref value_at/value_of 0 T F(T&) F(T) 1 T& F(T&) F(T&) This, I repeat, is the only sensible behavior. If we make value_at/value_of behave the same as at/deref, then we can never know the exact type of the elements in the source container if there are references involved. Given the "corrected" identity transform I attached in the trac ticket, the result of the as_vector will be as expected: vector<int, int&> (Both vector<int&, int&> and vector<int&, int&> results are wrong) For reference, here's the corrected identity transform: struct identity { template <class FunCall> struct result; template <class Fun, class T> struct result<Fun(T)> { typedef T type; }; template <class T> T& operator()(T& val) const { return val; } template <class T> T const& operator()(T const& val) const { return val; } }; Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
(Both vector<int&, int&> and vector<int&, int&> results are wrong)
Ooops, I meant: (Both vector<int&, int&> and vector<int, int> results are wrong) Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
shunsuke wrote:
Joel de Guzman wrote:
alas, this uncovers a bug in the implementation where value_at does not follow above. What is a bug?
See diff of the source in value_at_impl.hpp for the last 2 revisions.
Is there any pitfall if `value_at` is the same as `at` under transform_view?
After some more thinking, yes.
I still don't know why, but I know you are always right.
You got me thinking though. It could very well be that you are correct! Perhaps we need the same behavior for both at/deref and value_at/value_of. My thinking, OTOH, is that both should get the value_at of the underlying sequence. Hence, transform(vector<int, int&>, f) will trigger f this way:
int ---> f::result<f(int)> int& ---> f::result<f(int&)> No, when vector<int, int&> is mutable lvalue, f should be able to access the mutable int. Hence,
int --> f::result<f(int&)> int& --> f::result<f(int&)>
I think you are missing the point. It is always mutable with deref and at. value_at and value_of should allow you to get the *actual* type of the underlying sequence. Think of value_at and value_of as having copy semantics.
I understood it probably. If as_vector means "copy", rvalue should be passed to FunctionObject. In fact, I'm trying to implement "zip". If interested, see: http://tinyurl.com/22q6cl as_vector intercepts mutability. I'm now lost, but I will retry. I really apologize my mega-noise. Regards, -- Shunsuke Sogame

shunsuke wrote:
Joel de Guzman wrote:
Is there any pitfall if `value_at` is the same as `at` under transform_view? After some more thinking, yes.
I still don't know why, but I know you are always right.
Nah. No one's always right ;-) I'm always open to discussions like this.
I understood it probably. If as_vector means "copy", rvalue should be passed to FunctionObject.
In fact, I'm trying to implement "zip". If interested, see: http://tinyurl.com/22q6cl as_vector intercepts mutability. I'm now lost, but I will retry.
Dan Marsden probably faced the same problems as you when he implemented fusion zip. I'm CC'ing him. I think he's the best person to ask questions. In the meantime, you might want to take a look at fusion zip.
I really apologize my mega-noise.
Hey, I really appreciate discussions like this. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
participants (2)
-
Joel de Guzman
-
shunsuke