mdarray: Explain why we omit reshape / resize
Nobody has claimed this yet.
- Dominant language
- HTML
- Stars
- 29
- Forks
- 26
- PR merge metrics
- No merged PRs in 30d
Description
Why mdarray omits reshape / resize
Some users have asked why mdarray does not have a "reshape" or "resize" function. This would change the extents of an existing mdarray "in place," like vector::resize. We should add text to P1684 explaining why mdarray does not have these functions. Here is a draft of this text.
Reasons not to add a reshape / resize member function to mdarray
- The function would only make sense if the mdarray has at least one dynamic extent.
- An mdarray can have dynamic extents but still use a bounded container type like
std::array. Thus, the reshape operation's preconditions would depend on the container type, making it more difficult to write generic code. mdarray would also need a new concept to know whether the container has aresizemethod (or some other way to resize). - Resizing an mdarray would invalidate existing views, during the lifetime of the mdarray being viewed. (
vectorhas the same problem.) - If the mdarray's container is
vector, then resizing / reshaping would double-initialize the new elements. This is one justification for thestd::string::resize_and_overwritemember function in C++23. - C++ arguably should have standardized a dynamically sized, non-resize-able array type, to fill the gap between
array(fixed compile-time size, O(size()) move cost) andvector(arbitrarily resize-able, O(1) move cost). mdarray is the multidimensional analogy of this missing type in the C++ Standard Library.
What about a nonmember function?
We could consider a nonmember reshape function that can consume and recycle an existing mdarray's storage, if reuse is possible.
template<class ElementType, class InExtents, class Layout, class Container, class OutputIndexType, size_t ... OutputExtents>
mdarray<ElementType, extents<OutputIndexType, OutputExtents...>, Layout, Container>
reshape(mdarray<ElementType, InExtents, Layout, Container>&& recycle_me,
extents<OutputIndexType, OutputExtents...> e,
ElementType default_fill_value = ElementType{});
This would permit changing the extents, even if all the input extents are static. After return, the input mdarray would be in that uncomfortable moved-from state, but mdarray already has move constructors and move assignment, so this is not a new discomfort.
Note that there's no way for users to define reshape in a way that can reuse the container's storage. This is because mdarray does not expose access to the underlying container after mdarray construction. (This was a P1684R2 change.)
What about a different container?
Above, I pointed out that C++ arguably should have standardized a dynamically sized, non-resize-able array type, to fill the gap between array (fixed compile-time size, O(size()) move cost) and vector (arbitrarily resize-able, O(1) move cost). mdarray is the multidimensional analogy of this missing type in the C++ Standard Library.
I do agree that it's convenient to be able to reshape an existing container in place. I've certainly written Matlab code that adds a new column to a matrix now and then. However, there's no need for this reshape-able container to be named "mdarray." In general, we shouldn't necessarily be shy in defining new container types. The fundamental vocabulary type is the view, not the container. Different container types communicate with algorithms through mdspan, which is the common interface between containers and algorithms-on-views-of-data. Algorithms that operate on views-of-data should take mdspan . Containers should define a way to get an mdspan viewing the container's data.
Forcing mdarray to be the dynamically reshape-able container could prevent optimizations. For example, a dynamically reshape-able container need not even use contiguous storage. It might store add-ons as separate allocations, and then have a "pack" operation that transforms it into a single contiguous allocation. This could reduce intermediate reallocation costs.
// mdarray<...> pack(dyanmic_mdarray<...>&&);
dynamic_mdarray A_dynamic{...};
while(some_condition()) {
auto new_column = allocate_and_compute_new_column(A_dynamic.extent(0));
// 1 is the extent to which to append the column
A_dynamic.append(1, std::move(new_column));
}
auto A_packed = pack(A_dynamic);
some_algorithm_taking_mdspan(A_packed.mdspan());
This is analogous to the "string builder" vs. string distinction.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Locate the P1684 paper in the repository and review its existing discussion of mdarray, reshape, and resize. Add the supplied rationale and alternatives in the appropriate section, then verify that the paper clearly explains why these functions are omitted and that its formatting remains consistent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100