Add MoveAssignable to resource object types

Issue #189 resolved
Dan Bonachea created an issue

Currently our resource object types like team, atomic_domain, cuda_device and device_allocator are MoveConstructible but not MoveAssignable.

Move construction and move assignment are semantically very similar operations, the main difference to the latter is the target object already exists and might have some associated state. However MoveAssignable gives the user significantly more flexibility in structuring their code. I've encountered a number of cases where the user is forced into adding dynamic allocation and a level of indirection just to circumvent this awkward and arbitrary restriction of ours.

The code required to support MoveAssignment should be nearly identical to the code we already need to support MoveConstruction. Whatever preconditions and restrictions currently apply to MoveConstruction (notably for team) would also apply to MoveAssignment. I think we might just need to specify what it "means" to overwrite an active target object (which could be as simple as saying the object states are swapped).

Assuming we decide to pursue this idea, we should also consider the synergistic enhancement of adding DefaultConstructible to team and atomic_domain that construct an "inactive" object, allowing the user the convenience of statically declaring an object placeholder that will later be overwritten with the real resource object prior to use.

Along similar lines, we should also consider adding MoveAssignment to dist_object (when the encapsulated type is MoveAssignable).

Comments (5)

  1. Dan Bonachea reporter

    This was discussed in our 2022-02-23 meeting

    Notes:

    • We want to support move-assign onto a default-allocated "inactive" object
      • Most useful if we also make team and atomic_domain default constructible
      • probably also need an is_active() query to go with this
    • we favor the simple semantic approach: preconditions that the LHS target object is inactive
      • assert that target object is inactive
    • dist_object
      • no concept of inactive because there's no "resource" aside from the value
      • maybe provide DefaultConstructor for DefaultConstructible T
      • maybe provide moveassignment when T is MoveAssignable
      • move constructor requires master persona, to update registration, move assignment would have same precondition
  2. Dan Bonachea reporter

    Amir will be working on this.

    The plan, based on our Zoom discussion today (and some of my own extrapolation):

    1. Deploy non-collective default constructors (usable before init) and is_active queries to team, atomic_domain , device_allocator and {cuda,hip}_device
      • default allocation creates an inactive object
      • the memory kinds classes have all of this except "usable before init" on default constructor
    2. Update current spec language for team and atomic_domain objects "invalid" -> "inactive"
      • i.e. an "inactive" team or atomic_domain object is still a "valid" state in the C++ sense
      • team_id() still creates an "invalid" team_id
    3. Deploy move assignment operators to all the classes above
      • precondition is LHS is inactive, and existing preconditions copied from move constructor
      • sets RHS to inactive
    4. Delay changes to device_allocator and {cuda,hip}_device until the in-flight memory kinds PRs are merged, to avoid conflicts
    5. Defer any changes to dist_object, likely until after the current release
  3. Dan Bonachea reporter

    Another detail:

    As part of this work I think we should specify that atomic_domain::destroy() and team::destroy() both transition objects to a valid but inactive state (equivalent to a default-constructed object). Both classes currently need minor changes in the destroy implementation to deploy this.

    We should also clarify what it means to destroy() an inactive atomic_domain. I suggest we handle it the same as team::destroy() on an "invalid" team, ie a non-collective no-op.

  4. Log in to comment