Skip to content

details: noexcept specification for transform sender#396

Open
maartenarnst wants to merge 3 commits into
mainfrom
noexcept
Open

details: noexcept specification for transform sender#396
maartenarnst wants to merge 3 commits into
mainfrom
noexcept

Conversation

@maartenarnst

Copy link
Copy Markdown
Collaborator

Comment thread kokkos_ext/impl/execution_space/domain.hpp Outdated
struct transform_sender_for<Kokkos::Experimental::parallel_for_t, Env> {
template <typename Data, execution_space_completing_sender<Env> Sndr>
auto operator()(Kokkos::Experimental::parallel_for_t, Data&& data, Sndr&& sndr) const noexcept {
auto operator()(Kokkos::Experimental::parallel_for_t, Data&& data, Sndr&& sndr) const

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about:

template <typename Env>
struct transform_sender_for<Kokkos::Experimental::parallel_for_t, Env> {
private:
    template <typename Data, typename Sndr>
    auto impl(Data&& data, Sndr&& sndr) const {
        auto [label, functor, policy] = std::forward<Data>(data);

        using functor_t = decltype(functor);
        using policy_t  = decltype(policy);

        auto schd = stdexec::get_completion_scheduler<stdexec::set_value_t>(
            stdexec::get_env(sndr), env_);

        policy_t policy_updated(Kokkos::Impl::PolicyUpdate{}, std::move(policy), schd.state->exec);
        return ParallelForSender<Sndr, functor_t, policy_t>{
            {{std::move(label), std::move(functor), std::move(policy_updated)}},
            std::forward<Sndr>(sndr)};
    }

public:
    template <typename Data, execution_space_completing_sender<Env> Sndr>
    auto operator()(Kokkos::Experimental::parallel_for_t, Data&& data, Sndr&& sndr) const
        noexcept(noexcept(impl(std::forward<Data>(data), std::forward<Sndr>(sndr)))) {
        return impl(std::forward<Data>(data), std::forward<Sndr>(sndr));
    }

    const Env& env_; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
};

@maartenarnst maartenarnst force-pushed the noexcept branch 3 times, most recently from c3486ed to 9e95eeb Compare February 20, 2026 10:46
Comment thread tests/kokkos_ext/execution_space/test_bulk.cpp Outdated
struct transform_sender_for<Kokkos::Experimental::parallel_for_t> {
template <typename Env, typename Data, execution_space_completing_sender<Env> Sndr>
auto operator()(const Env& env, Kokkos::Experimental::parallel_for_t, Data&& data, Sndr&& sndr) const noexcept {
auto operator()(const Env& env, Kokkos::Experimental::parallel_for_t, Data&& data, Sndr&& sndr) const

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this version still isn't bringing anything new on the table.

I find it ever worse in terms of:

  • readability
  • contract

I think you should either drop the noexcept, or make it unconditional with static_assert inside. Any other attempt will make the noexcept look weird w.r.t. the body, so any develop would look at it suspiciously and want to audit it.

How about:

template <>
struct transform_sender_for<Kokkos::Experimental::parallel_for_t> {
    template <typename Env, typename Data, execution_space_completing_sender<Env> Sndr>
    auto operator()(const Env& env, Kokkos::Experimental::parallel_for_t, Data&& data, Sndr&& sndr) const noexcept {
        auto [label, functor, policy] = std::forward<Data>(data);

        using policy_t  = decltype(policy);
        using functor_t = decltype(functor);
        using closure_t = ParallelForClosure<functor_t, policy_t>;
        using sender_t  = ParallelForSender<Sndr, functor_t, policy_t>;

        static_assert(std::is_nothrow_move_constructible_v<policy_t>,
            "parallel_for_t transform: policy must be nothrow move constructible");
        static_assert(std::is_nothrow_constructible_v<closure_t, std::string, functor_t, policy_t>,
            "parallel_for_t transform: closure must be nothrow constructible from its members");
        static_assert(std::is_nothrow_constructible_v<sender_t, closure_t, Sndr>,
            "parallel_for_t transform: ParallelForSender must be nothrow constructible");

        auto schd = stdexec::get_completion_scheduler<stdexec::set_value_t>(stdexec::get_env(sndr), env);
        auto new_policy = policy_t(Kokkos::Impl::PolicyUpdate{}, std::move(policy), schd.state->exec);

        auto clsr = closure_t{{std::move(label), std::move(functor), std::move(new_policy)}};

        return sender_t{std::move(clsr), std::forward<Sndr>(sndr)};
    }
};

Basically, you mandate that everything you build must not throw, and you add stat_assert in the body to ensure that contract is respected.

Side question: what's the benefit of nothrow connectability ? Worth added to the documentation somewhere probably.

@maartenarnst maartenarnst force-pushed the noexcept branch 2 times, most recently from 72e70ab to 863a6d3 Compare February 22, 2026 13:18
@maartenarnst maartenarnst force-pushed the noexcept branch 2 times, most recently from f582cdb to d8e085b Compare February 23, 2026 11:57
Comment thread kokkos_ext/impl/execution_space/parallel_for.hpp
@maartenarnst maartenarnst force-pushed the noexcept branch 3 times, most recently from 61d597c to 9bf7d32 Compare February 23, 2026 17:30
romintomasetti added a commit that referenced this pull request Feb 23, 2026
Extracted from:
* #396

Signed-off-by: romintomasetti <romin.tomasetti@gmail.com>
@maartenarnst maartenarnst force-pushed the noexcept branch 2 times, most recently from bf491c4 to d2be6a1 Compare February 23, 2026 17:54
@maartenarnst maartenarnst requested a review from Copilot February 23, 2026 17:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive noexcept specifications to transform_sender and connect functions for sender/receiver operations, ensuring proper exception handling guarantees in the stdexec framework integration. The changes align with standard C++ practices for expressing exception specifications and enable compile-time detection of potential exceptions.

Changes:

  • Added noexcept specifications to transform_sender and connect functions using stdexec traits (__nothrow_applicable, __nothrow_connectable, __nothrow_decay_copyable)
  • Refactored code to use type aliases for improved readability and correct noexcept expression evaluation
  • Added tests to verify noexcept behavior with different view types (Kokkos::View vs std::span)

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/stdexec/inline_scheduler_with_domain.hpp Added noexcept specifications to transform_sender and connect; fixed requires clause to use Sndr&& instead of Sndr
tests/kokkos_ext/execution_space/test_parallel_for.cpp Added compile-time tests for noexcept transformability with different view types
kokkos_ext/impl/execution_space/scoped_region.hpp Added type aliases and noexcept specification to connect; updated get_completion_scheduler call to include receiver environment
kokkos_ext/impl/execution_space/schedule_from.hpp Added type alias and noexcept specification to connect
kokkos_ext/impl/execution_space/parallel_for.hpp Added noexcept specification to transform_sender operator; refactored with type aliases and helper function for policy update
kokkos_ext/impl/execution_space/continues_on.hpp Added type alias and noexcept specification to connect; moved member declaration
kokkos_ext/impl/execution_space/bulk.hpp Added noexcept specification to transform_sender operator; refactored with type aliases and helper function for policy construction

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/stdexec/inline_scheduler_with_domain.hpp
Comment thread tests/kokkos_ext/execution_space/test_parallel_for.cpp Outdated
template <stdexec::receiver Rcvr>
stdexec::operation_state auto connect(Rcvr rcvr) && noexcept(
std::is_nothrow_constructible_v<
rcvr_t<schd_t<::stdexec::env_of_t<Rcvr>>, Rcvr>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about you make schd_t take the receiver instead of the env ? It would shorten the whole thing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then rcvr_t could also just take the receiver, and deduce the scheduler. Makes the whole thing really shorter.

Comment thread kokkos_ext/impl/execution_space/parallel_for.hpp
* despite not having a @c noexcept specification.
*/
template <Kokkos::ExecutionPolicy ExecPolicy>
static auto impl_policy_construct(const auto& exec, auto shape) noexcept {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, not all policies are no throw constructible. I'm thinking of the range polices on GPUs that need to check for block/grid size.

But I guess a failure in the construction of an execution policy is a hard failure (not sure it's easy or worth to recover from it), so marking noexcept will make it terminate and that's probably fine.

It's worth opening an issue on the Kokkos side and enhance a bit your docstring with my comment ;)

Comment thread kokkos_ext/impl/execution_space/bulk.hpp
Comment thread kokkos_ext/impl/execution_space/parallel_for.hpp
@maartenarnst maartenarnst force-pushed the noexcept branch 2 times, most recently from eb923cd to d4959f4 Compare February 24, 2026 15:51
Comment thread tests/kokkos_ext/Helpers.hpp Outdated
Comment thread tests/Functors.hpp Outdated
Comment thread kokkos_ext/impl/bulk.hpp
//! See https://github.com/NVIDIA/stdexec/blob/16076a81efa4477513e6ede9c2741fd034ecef99/include/stdexec/__detail/__bulk.hpp#L100.
template <typename Data>
concept has_parallel_policy = requires(const Data& data) {
concept has_parallel_policy = requires(const std::remove_cvref_t<Data>& data) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this one?

return sndr_t<Sndr, Functor, Env>{
{{std::string(std::format("{}: then", Kokkos::Impl::TypeInfo<execution_space<Sndr, Env>>::name())),
ThenWrapper{std::forward<Functor>(functor)},
ThenWrapper<std::remove_cvref_t<Functor>>{.functor = std::forward<Functor>(functor)},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have a then_wrapper_t so that you have a single, centralized place where you can document why we need to remove the reference. BTW I'd do remove_ref_t only (?).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a static assert to the then wrapper itself with a comment.

@maartenarnst maartenarnst force-pushed the noexcept branch 2 times, most recently from 5891510 to f347b79 Compare February 25, 2026 16:42
Signed-off-by: Maarten Arnst <maarten.arnst@uliege.be>
Signed-off-by: Maarten Arnst <maarten.arnst@uliege.be>
@maartenarnst maartenarnst force-pushed the noexcept branch 7 times, most recently from 5b26fe1 to 5a526e1 Compare March 2, 2026 14:49
maartenarnst pushed a commit that referenced this pull request Mar 4, 2026
Extracted from:
* #396

Signed-off-by: romintomasetti <romin.tomasetti@gmail.com>
maartenarnst pushed a commit to uliegecsm/kokkos-execution that referenced this pull request Mar 4, 2026
Extracted from:
* uliegecsm/graph-dispatching#396

Signed-off-by: romintomasetti <romin.tomasetti@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants