These are chat archives for boostorg/hana

14th
Jan 2016
Louis Dionne
@ldionne
Jan 14 2016 00:01
@ricejasonf Technically, you can achieve this with std::ref, but you’ll end up with reference wrappers instead of actual references.
Jason Rice
@ricejasonf
Jan 14 2016 00:06
@ldionne Yes, I'm going to play around with that.
Louis Dionne
@ldionne
Jan 14 2016 00:17
References are damn pests. They are very useful, but they just don’t behave like objects… Same problem in the STL.
Barrett Adair
@badair
Jan 14 2016 00:20
I agree 100%. reference_wrapper is a decent bandaid, but the lack of ability to :: them makes them unappealing for metaprogramming.
The fact that you dont get implicit conversions on the SR operator isn't reference wrapper's fault, though
Louis Dionne
@ldionne
Jan 14 2016 00:21
SR operator?
Barrett Adair
@badair
Jan 14 2016 00:22
Scope resolution? Thats what I've always called it. ::
Louis Dionne
@ldionne
Jan 14 2016 00:22
Oh, I couldn’t understand the accronym
Barrett Adair
@badair
Jan 14 2016 00:22
Sorry, on mobile
Louis Dionne
@ldionne
Jan 14 2016 00:22
No problem
Jason Rice
@ricejasonf
Jan 14 2016 04:35
I played around with hana::partial and std::ref. It yielded nothing other than a slightly slower compile time. I also forgot that my stuff is, for the most part, empty. (Although the whole tree probably adds up to like 50-100 bytes)
Jason Rice
@ricejasonf
Jan 14 2016 04:43
It also couldn't be used in only some of the constexprs which was weird. https://gist.github.com/ricejasonf/78f62e74d9dec0d72bbf
Barrett Adair
@badair
Jan 14 2016 05:11
Are you familiar with the implementation of std::ref/cref and std::reference_wrapper?
If not, it might bring some clarity to issues you encounter. It's been some time since I've read the specs on them, but they are actually really simple
Barrett Adair
@badair
Jan 14 2016 05:22
Is the code you posted
(Sorry, didn't mean to send that)
Barrett Adair
@badair
Jan 14 2016 05:30
I honestly don't see a way to implement a perfect forwarding version of hana::partial without resorting to heavy type manipulation and lots of additional code I think
(Man this chat thing is touchy)
...I think it's probably in Hana's best interest to document hana::partial as a value-only tool, and to use a reference_wrapper for references
Barrett Adair
@badair
Jan 14 2016 05:36
And to forget about a perfect forwarding partial. I know how I would implement it, but it would be a lot of code for an edge use case. The idea of reference forwarding in a partial application is kind of silly, since the reference needs to be in scope anyway.
TLDR; +1 for reference_wrapper
Barrett Adair
@badair
Jan 14 2016 05:45
I will try to implement a perfect forwarding partial application in my project when i finish the changes I'm in the middle of making. I will let you know if I succeed
Louis Dionne
@ldionne
Jan 14 2016 16:33

I think a perfect forwading partial would be easy to achieve. Go look at the rest of partial's implementation, but we would most likely need the following only:

template <std::size_t ...n, typename F, typename ...X>
struct partial_t<std::index_sequence<n...>, F, X...> {
    // ... same as before ...

    // Here, instead of storing actual values, store references
    basic_tuple<F, X&&...> storage_;

    // ... same as before ...
};

So I don't think the problem is the implementation complexity, but rather the use case we'd have for this, and how to make this variant of partial available without making the interface more complex (so without adding partial_ref).

Barrett Adair
@badair
Jan 14 2016 16:36
how would you put lvalue references in the tuple above? X&& is not a universal reference - right?
Thats the heart of the problem, afaik
Louis Dionne
@ldionne
Jan 14 2016 16:38
I think it would work if make_partial did not decay the arguments
Since X would be a reference type (some T&), and then X&& would be T& &&, which collapses to T& by reference collapsing rules.
Barrett Adair
@badair
Jan 14 2016 16:38
That makes sense
Same logic as std::forward
Louis Dionne
@ldionne
Jan 14 2016 16:39
Yyes.
Barrett Adair
@badair
Jan 14 2016 16:41
Wouldn't you still need to move-construct from rvalue references? For safety? And then re-move on the re-forward?
Or probably const ref on the re-forward
That's a difficult decision, since you can't bind crefs to rrefs, but you can do the opposite. So it depends on the signature of the hosted callable
Right?
Did that make sense?
Louis Dionne
@ldionne
Jan 14 2016 17:40
partial would only hold references, and it would assume that whatever the references point to are in scope for the whole lifetime of the partial object. So there would be no need to move-construct any actual objects. One way to think of it is like if partial was holding pointers to external objects. No need to move construct anything there.
Now, if you had const refs and you did not use decay when creating partial_t<…>, you would end up with T const& &&, which collapses to T const&, and it would still work. At least, AFAICT.
Note that we wouldn’t be using std::cref or std::ref at all to implement this.
Barrett Adair
@badair
Jan 14 2016 17:43
When are destructors called on prvalues? E.g. the second argument to hana::partial(f, foo{})
That was my concern
You know more about storing references to rvalues than I do.
Barrett Adair
@badair
Jan 14 2016 17:51
And yes, we are on the same page - i meant for "cref" to be shorthand for const lvalue reference, not the library function. That was confusing
Louis Dionne
@ldionne
Jan 14 2016 17:51
Ok, in hana::partial(f, foo{}), hana::partial would store a rvalue-reference to the foo{} temporary. Of course, this reference is valid exactly until the temporary is destructed. However, the lifetime of a temporary is until the end of the enclosing expression. So, for example, consider some_algorithm(sequence, hana::partial(f, foo{})). hana::partial holds a rvalue reference to the foo{} temporary. Then, this partial is used by some_algorithm, which is fine because the temporary is still in scope. Then, the algorithm returns and the temporary goes out of scope, which is fine.
Basically, what you couldn’t do if we stored rvalue references in partial is the following: auto p = hana::partial(f, foo{}); use(p);. This is because by the time p is used (and hence the rvalue reference to foo{} accessed), foo{} has gone out of scope.
Barrett Adair
@badair
Jan 14 2016 17:53
Ok, that's what I thought. So you just wouldn't keep the partial object around. Got it
Louis Dionne
@ldionne
Jan 14 2016 17:53
Right.
That is, at least, my understanding of temporary lifetime.
But I could be wrong. C++ is complicated :)
Barrett Adair
@badair
Jan 14 2016 17:55
Indeed. I wasn't sure if it was expression-level or scope-level for prvalues.
Louis Dionne
@ldionne
Jan 14 2016 18:07
I’m pretty sure it’s expression-level.
Barrett Adair
@badair
Jan 14 2016 18:17
I wonder whether it would be nice to enable the use to specify the forward semantics with a wrapper function. Such as hana::partial(f, hana::move_then_copy(foo{})); Or even a generic function taking a template tag. Verbose, but granular, and could be specialized over the existing impl.
*the user
That allows for customization over "copy only" partial/"ref only" partial. Just an idea
Barrett Adair
@badair
Jan 14 2016 18:29
Users who happen to need more granularity than the existing implementation will probably appreciate that
Louis Dionne
@ldionne
Jan 14 2016 19:43
I have one thing in mind. We could allow hana::partial(f, std::ref(x)) to store a reference instead of a reference_wrapper. If we supported the special semantics for make_xxx(std::ref(…)) discussed in boostorg/hana#176, it would be very easy to implement this in hana::partial (because hana::partial stores the arguments in a tuple). However, this hits the same wall as #176, which is storing references in containers at all.
Jason Rice
@ricejasonf
Jan 14 2016 19:52
Wouldn't it also be a problem if f was actually expecting an std::ref(x)?
Barrett Adair
@badair
Jan 14 2016 19:54
I would be tempted to file that in the "too bad" folder :)
Jason Rice
@ricejasonf
Jan 14 2016 19:57
I guess you could do hana::partial(hana::make_pair, hana::dont_unwrap_me(std::ref(x))) :P
Louis Dionne
@ldionne
Jan 14 2016 20:07
Well, you can construct a std::reference_wrapper<T> from a T&, so it would work.
Jason Rice
@ricejasonf
Jan 14 2016 20:07
ahh
Barrett Adair
@badair
Jan 14 2016 20:08
I didn't realize the conversion worked both ways
Jason Rice
@ricejasonf
Jan 14 2016 20:08
are you saying that f would do that?
Louis Dionne
@ldionne
Jan 14 2016 20:08
Yes, it does. And both are implicit.
@ricejasonf I’m just saying that if f takes a reference_wrapper, and partial turns reference_wrappers into actual refs, then f would be called with actual refs.
But it would be fine, since (what I said).