Date: Mon, 14 Oct 2024 11:52:53 +0200
Hi,
In the absence of a reply, I suppose that the next step is to propose a
draft proposal for this idea?
Any other feedback in the meantime would be most welcome!
Thanks
Corentin Adam
Le sam. 28 sept. 2024 à 06:12, Corentin Adam <corentin.adam27_at_[hidden]> a
écrit :
> Thanks for your reply!
>
> First of all, indeed adding `from_range` to the constructor makes sense.
>
> Secondly, you seem to understand the proposal perfectly and your
> `when_all` example summarizes the same algorithm as what I've called
> `ranges::collect`.
> However, `ranges::collect` has more features that I think are useful. For
> example, `ranges::collect` works with any potential_type (i.e. any type
> that works like `std::optional` or `std::expected`), can build any
> container and you can pass container arguments as arguments to the function
> (as I mentioned, this is really inspired by ranges::to).
> You can read more about these capabilities in the README of my GitHub
> repos here
> <https://github.com/jileventreur/collect/blob/master/README.md#possibilities>
> .
>
> As for the function name itself, I'm not entirely convinced that `collect`
> is the most expressive, but on the other hand, I think `when_all` doesn't
> emphasize the container-building action performed by the function. But this
> is a secondary point that should be discussed later if discussions on the
> proposal go further.
>
> Concerning `when_any`, it's true that it's more or less the opposite of
> `collect` or `when_all`, but it adds real value to add this function
> compared to a simple find.
>
> I think that `ranges::collect/when_all` or the equivalent constructor
> approach suggested by Barry is the most common way of handling a range of
> “potential types”: if an error occurs, we abandon the process and handle
> the error.
> The other two possibilities, in my opinion, are:
> * ignore errors and collect valid values (and this is made easy by `
> p3168r1
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3168r1.html>:
> range support for optional` as seen in the first example shown in the paper)
> * separate errors and valid values and process them separately. This can
> already be done easily with std::partition.
>
> I agree with you that the constructor used in the ranges::to approach
> suggested by Barry can be confusing for the user and I tend to prefer the
> “when_all/collect” free function approach I suggested in the first place
> for the time being because it is more explicit for users.
> However, to be fair, I looked into the rust `collect` function to
> understand how it works on optional or expected and it is indeed done using
> a “constructor” (actually an implementation of the FromIterator trait)
> implemented in their equivalent expected/optional types.
> So `collect` in Rust works exactly like std::ranges::to and the “when_all”
> algorithm I want to add is done in Rust in the way Barry suggests.
> In Rust, this is common usage and anyone who calls collect on a
> `range<optional<value>>` to create an `optional<container<value>` knows
> that the result construction will follow the `when_all` behavior. Perhaps
> this would be less obvious to cpp developers, as it's not a language
> feature from scratch as it is in Rust.
> About `std::ranges::to<std::optional>()` this CTAD behavior might simply
> be unallowed I think (i.e. no CTAD for this optional/expected constructor)
> so I'm not sure that invalidates the constructor approach. If you fully
> specify the form of the output (e.g.
> `std::ranges::to<optional<vector<int>>>()`), the “when_all” behavior will
> occur. And because of the function's output type, it's impossible to expect
> the when_any behavior you mentioned..
>
> In any case, do you think either approach is worth proposing? I still
> think it's generally necessary when working with a “potential_type” range,
> and that it's missing from the current standard. If it's worthwhile, what
> should I do next, and would someone more experienced than me be so kind as
> to help me with this process?
>
> Thank you,
>
> Corentin Adam
>
> Le ven. 27 sept. 2024 à 23:06, Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
> a écrit :
>
>> On Thu, Sep 26, 2024 at 5:07 PM Corentin Adam via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> I hadn't thought of it that way, but I agree with you that it would work
>>> too.
>>> If I understand correctly, you mean some range constructors like this
>>> <https://godbolt.org/z/KGvaGboG7>?
>>>
>>
>> Presumably more like this <https://godbolt.org/z/Tbe1jcvEr>. (The only
>> diff is the addition of `from_range_t`.)
>>
>> IIUC, the proposal is to take a range of optionals and collapse it into
>> an optional of range, with this signature and semantics (if not this exact
>> name):
>>
>> std::optional<std::vector<T>> when_all(std::vector<std::optional<T>> v) {
>> if (std::ranges::all_of(v, [](auto&& x) { return bool(x); })) {
>> return v | std::views::transform([](auto&& o) { return *o; }) |
>> std::ranges::to<std::vector<T>>();
>> } else {
>> return std::nullopt;
>> }
>> }
>>
>> The obvious next step after `when_all` is `when_any`:
>>
>> std::optional<T> when_any(std::vector<std::optional<T>> v) {
>> auto it = std::ranges::find(v, true);
>> return (it == v.end()) ? *it : std::nullopt;
>> }
>>
>> Now, I don't think either of these is suitable for `ranges::to`, because
>> then what would happen when I write `std::ranges::to<std::optional>()`?
>> Just specifying the *shape of the output* isn't sufficient to tell me
>> (as the code-writer or as the code-reader/reviewer) what *algorithm* I
>> want (or expect) to be used to get the data into that shape. When the
>> algorithm is non-obvious, and/or when there's more than one possible
>> algorithm that could be used, the Standard Library should explicitly name
>> the algorithm.
>>
>>
>> Coincidentally, it was noted on the cpplang Slack just a day or two ago
>> that
>> // https://godbolt.org/z/1a6xcohTn
>> char hello[] = "hello";
>> auto s1 = hello | std::ranges::to<std::string>();
>> auto s2 = hello | std::views::all | std::ranges::to<std::string>();
>> assert(s1 != s2);
>> which is kind of another case of "when there's multiple possible ways to
>> do a transformation, it's confusing to give them all the same name."
>>
>> –Arthur
>>
>>
>>
>> On Thu, Sep 26, 2024 at 5:07 PM Corentin Adam via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> I hadn't thought of it that way, but I agree with you that it would work
>>> too.
>>> If I understand correctly, you mean some range constructors like this
>>> <https://godbolt.org/z/KGvaGboG7>?
>>>
>>> I've searched through the current proposals and it seems to me that
>>> these constructors haven't been proposed yet (even in the optional range
>>> support proposal), have they?
>>> If they haven't yet been proposed, what do you think about drafting a
>>> proposal to include them?
>>>
>>> Another question, why favor the constructor from ranges approach over
>>> the collect free function approach?
>>>
>>> Le mer. 11 sept. 2024 à 19:47, Barry Revzin <barry.revzin_at_[hidden]> a
>>> écrit :
>>>
>>>> On Wed, Sep 11, 2024, 11:56 AM Corentin Adam via Std-Proposals <
>>>> std-proposals_at_[hidden]> wrote:
>>>>
>>>>>
>>>>> I've recently been working on a cpp implementation of the rust collect
>>>>> function: :
>>>>> https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect.
>>>>>
>>>>> This function has two main uses in rust:
>>>>> * construct containers from ranges (exactly the work achieved by
>>>>> std::ranges::to)
>>>>> * collect ranges of expected/optional values into expected/optional
>>>>> range of value. Thus, if all values in the range are correct (in other
>>>>> words has_value() == true), the return value is true and contains the range
>>>>> of underlying values. Otherwise, the return value contains the first error
>>>>> encountered in the range.
>>>>>
>>>>
>>>> ranges::to can support the second use-case as well. We just need to add
>>>> the appropriate constructor to optional and expected.
>>>>
>>>> Barry
>>>>
>>>>> --
>>> Std-Proposals mailing list
>>> Std-Proposals_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>
>>
In the absence of a reply, I suppose that the next step is to propose a
draft proposal for this idea?
Any other feedback in the meantime would be most welcome!
Thanks
Corentin Adam
Le sam. 28 sept. 2024 à 06:12, Corentin Adam <corentin.adam27_at_[hidden]> a
écrit :
> Thanks for your reply!
>
> First of all, indeed adding `from_range` to the constructor makes sense.
>
> Secondly, you seem to understand the proposal perfectly and your
> `when_all` example summarizes the same algorithm as what I've called
> `ranges::collect`.
> However, `ranges::collect` has more features that I think are useful. For
> example, `ranges::collect` works with any potential_type (i.e. any type
> that works like `std::optional` or `std::expected`), can build any
> container and you can pass container arguments as arguments to the function
> (as I mentioned, this is really inspired by ranges::to).
> You can read more about these capabilities in the README of my GitHub
> repos here
> <https://github.com/jileventreur/collect/blob/master/README.md#possibilities>
> .
>
> As for the function name itself, I'm not entirely convinced that `collect`
> is the most expressive, but on the other hand, I think `when_all` doesn't
> emphasize the container-building action performed by the function. But this
> is a secondary point that should be discussed later if discussions on the
> proposal go further.
>
> Concerning `when_any`, it's true that it's more or less the opposite of
> `collect` or `when_all`, but it adds real value to add this function
> compared to a simple find.
>
> I think that `ranges::collect/when_all` or the equivalent constructor
> approach suggested by Barry is the most common way of handling a range of
> “potential types”: if an error occurs, we abandon the process and handle
> the error.
> The other two possibilities, in my opinion, are:
> * ignore errors and collect valid values (and this is made easy by `
> p3168r1
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3168r1.html>:
> range support for optional` as seen in the first example shown in the paper)
> * separate errors and valid values and process them separately. This can
> already be done easily with std::partition.
>
> I agree with you that the constructor used in the ranges::to approach
> suggested by Barry can be confusing for the user and I tend to prefer the
> “when_all/collect” free function approach I suggested in the first place
> for the time being because it is more explicit for users.
> However, to be fair, I looked into the rust `collect` function to
> understand how it works on optional or expected and it is indeed done using
> a “constructor” (actually an implementation of the FromIterator trait)
> implemented in their equivalent expected/optional types.
> So `collect` in Rust works exactly like std::ranges::to and the “when_all”
> algorithm I want to add is done in Rust in the way Barry suggests.
> In Rust, this is common usage and anyone who calls collect on a
> `range<optional<value>>` to create an `optional<container<value>` knows
> that the result construction will follow the `when_all` behavior. Perhaps
> this would be less obvious to cpp developers, as it's not a language
> feature from scratch as it is in Rust.
> About `std::ranges::to<std::optional>()` this CTAD behavior might simply
> be unallowed I think (i.e. no CTAD for this optional/expected constructor)
> so I'm not sure that invalidates the constructor approach. If you fully
> specify the form of the output (e.g.
> `std::ranges::to<optional<vector<int>>>()`), the “when_all” behavior will
> occur. And because of the function's output type, it's impossible to expect
> the when_any behavior you mentioned..
>
> In any case, do you think either approach is worth proposing? I still
> think it's generally necessary when working with a “potential_type” range,
> and that it's missing from the current standard. If it's worthwhile, what
> should I do next, and would someone more experienced than me be so kind as
> to help me with this process?
>
> Thank you,
>
> Corentin Adam
>
> Le ven. 27 sept. 2024 à 23:06, Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
> a écrit :
>
>> On Thu, Sep 26, 2024 at 5:07 PM Corentin Adam via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> I hadn't thought of it that way, but I agree with you that it would work
>>> too.
>>> If I understand correctly, you mean some range constructors like this
>>> <https://godbolt.org/z/KGvaGboG7>?
>>>
>>
>> Presumably more like this <https://godbolt.org/z/Tbe1jcvEr>. (The only
>> diff is the addition of `from_range_t`.)
>>
>> IIUC, the proposal is to take a range of optionals and collapse it into
>> an optional of range, with this signature and semantics (if not this exact
>> name):
>>
>> std::optional<std::vector<T>> when_all(std::vector<std::optional<T>> v) {
>> if (std::ranges::all_of(v, [](auto&& x) { return bool(x); })) {
>> return v | std::views::transform([](auto&& o) { return *o; }) |
>> std::ranges::to<std::vector<T>>();
>> } else {
>> return std::nullopt;
>> }
>> }
>>
>> The obvious next step after `when_all` is `when_any`:
>>
>> std::optional<T> when_any(std::vector<std::optional<T>> v) {
>> auto it = std::ranges::find(v, true);
>> return (it == v.end()) ? *it : std::nullopt;
>> }
>>
>> Now, I don't think either of these is suitable for `ranges::to`, because
>> then what would happen when I write `std::ranges::to<std::optional>()`?
>> Just specifying the *shape of the output* isn't sufficient to tell me
>> (as the code-writer or as the code-reader/reviewer) what *algorithm* I
>> want (or expect) to be used to get the data into that shape. When the
>> algorithm is non-obvious, and/or when there's more than one possible
>> algorithm that could be used, the Standard Library should explicitly name
>> the algorithm.
>>
>>
>> Coincidentally, it was noted on the cpplang Slack just a day or two ago
>> that
>> // https://godbolt.org/z/1a6xcohTn
>> char hello[] = "hello";
>> auto s1 = hello | std::ranges::to<std::string>();
>> auto s2 = hello | std::views::all | std::ranges::to<std::string>();
>> assert(s1 != s2);
>> which is kind of another case of "when there's multiple possible ways to
>> do a transformation, it's confusing to give them all the same name."
>>
>> –Arthur
>>
>>
>>
>> On Thu, Sep 26, 2024 at 5:07 PM Corentin Adam via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> I hadn't thought of it that way, but I agree with you that it would work
>>> too.
>>> If I understand correctly, you mean some range constructors like this
>>> <https://godbolt.org/z/KGvaGboG7>?
>>>
>>> I've searched through the current proposals and it seems to me that
>>> these constructors haven't been proposed yet (even in the optional range
>>> support proposal), have they?
>>> If they haven't yet been proposed, what do you think about drafting a
>>> proposal to include them?
>>>
>>> Another question, why favor the constructor from ranges approach over
>>> the collect free function approach?
>>>
>>> Le mer. 11 sept. 2024 à 19:47, Barry Revzin <barry.revzin_at_[hidden]> a
>>> écrit :
>>>
>>>> On Wed, Sep 11, 2024, 11:56 AM Corentin Adam via Std-Proposals <
>>>> std-proposals_at_[hidden]> wrote:
>>>>
>>>>>
>>>>> I've recently been working on a cpp implementation of the rust collect
>>>>> function: :
>>>>> https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect.
>>>>>
>>>>> This function has two main uses in rust:
>>>>> * construct containers from ranges (exactly the work achieved by
>>>>> std::ranges::to)
>>>>> * collect ranges of expected/optional values into expected/optional
>>>>> range of value. Thus, if all values in the range are correct (in other
>>>>> words has_value() == true), the return value is true and contains the range
>>>>> of underlying values. Otherwise, the return value contains the first error
>>>>> encountered in the range.
>>>>>
>>>>
>>>> ranges::to can support the second use-case as well. We just need to add
>>>> the appropriate constructor to optional and expected.
>>>>
>>>> Barry
>>>>
>>>>> --
>>> Std-Proposals mailing list
>>> Std-Proposals_at_[hidden]
>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>>
>>
Received on 2024-10-14 09:53:10