On 8/7/26 14:00, Matt Borland via Boost wrote:
Hello,
Today begins the mini-review of Multi, authored by Alfredo Correa. Multi is a modern C++ library that provides manipulation and access of data in multidimensional arrays for both CPU and GPU memory. The review will run through Wednesday 12 August.
You can find the library and documentation links below: - https://github.com/correaa/boost-multi - https://correaa.github.io/boost-multi/multi/intro.html
The review earlier this year raised a number of issues that primarily revolved around the state of the documentation, not the library itself. I have labeled all of the issues related to conditions found in last review, and many have notes or resolution from Alfredo:
https://github.com/correaa/boost-multi/issues?q=is%3Aissue%20state%3Aopen%20...
To this end the review will revolve around the current state of the documentation on the branch "boost_review". In your review please explicitly state if you recommend REJECT, ACCEPT, or a conditional acceptance along with the acceptance conditions.
Looking at the reference documentation (https://correaa.github.io/boost-multi/multi/reference/index.html), it's obviously incomplete. About half of the namespace-level symbols don't even have a short one-sentence description in the description column. Actually clicking on the specific symbols yields some additional information if you read between the lines, but not enough. It's also quite difficult to read, lacking cross-links and spreading minimal information across a maximal number of unique pages. I'll try to go through the namespace-level non-deprecated symbols one by one and document the main problems I find. I will be very specific because apparently my previous feedback was too vague. boost::multi::array (https://correaa.github.io/boost-multi/multi/reference/boost/multi/array-0ad....) is relatively well-documented, i.e. most members have at least a one-line description. Not all, mind you. Specific concerns: - A lot of basic usage information on this type is found elsewhere in the documentation, https://correaa.github.io/boost-multi/multi/reference.html#ref_types. This is not wrong per se, but there should be a link from the reference page to the page containing the information. Better still would be to make the API reference complete in itself. - There are typos. "multidimensionally" is misspelled as "mutidimensioally" several times. "associated" is misspelled "associalted". "yields" is misspelled "yeilds". - The following non-deprecated public symbols are not documented at all: flatted, flattened, is_flattable. - Protected symbols are included symbols are included in the documentation. Why? Are they part of the public API? Are users supposed to create classes that derive from `array`? - Some symbols have "<symbol_name> overloads" as their short description. Surely these overloads have enough in common to share a single description that's actually descriptive? - The documentations for operators [] and () is particularly bad. Logically speaking, these are not overloaded sets but single functions with a variable number of arguments. I don't need a list of which overloads were used to implement them. I need a description of what kinds of arguments they accept (single indices and ranges) and what they return (subarray view or reference to element). - Function that return a type defined anywhere in the library, or accept an argument of a type defined anywhere in the library, should link to the documentation of that type. - Type aliases that alias a type defined elsewhere in the library should link to the documentation of that type. - What does "yields a view in which indices are unordered (generally to optimize access)" mean? Indices can be reordered, arbitrarily so, but they cannot be unordered. Indices are always in an order. - Operators are split between member functions and non-member functions, which makes it difficult to see which operators exist at a glance. - I don't care about friendship relations between types. That's an implementation detail that does not need to be documented. boost::multi::array_ref (https://correaa.github.io/boost-multi/multi/reference/boost/multi/array_ref-...): pretty much the same concerns as for boost::multi::array. In addition: - `iterator` has no description. - `layout_type` has no description. - `value_type` has no description. - `base` has no description. - `begin` has no description. - `data_elements` has no description. - `dropped` has no description. - `end` has no description. - `swap` has no description. This is particularly bad because there are three possible interpretations of what this function can do: - It could swap which underlying arrays two array_refs point to, leaving the underlying arrays unchanged, in violation of the guarantee that array_refs cannot be rebound. - It could cheaply swap the data stores of the underlying arrays. - It could not-so-cheaply swap every corresponding element of the underlying arrays. boost::multi::array_types (https://correaa.github.io/boost-multi/multi/reference/boost/multi/array_type...): this class looks like an implementation detail which exists in order to support its derived class, const_subarray. If so, it should be removed from the documentation entirely. boost::multi::bind_category (https://correaa.github.io/boost-multi/multi/reference/boost/multi/bind_categ...): again, no description. Document properly if part of the public API, else remove. boost::multi::bind_front_t (https://correaa.github.io/boost-multi/multi/reference/boost/multi/bind_front...): I can't make out the purpose of this class. There is no description, and the description of its only member function is useless. If this is another implementation detail, it should be removed from the documentation. If it's part of the public API, it should be documented properly. boost::multi::bind_transposed_t (https://correaa.github.io/boost-multi/multi/reference/boost/multi/bind_trans...): see boost::multi::bind_front_t. boost::multi::const_subarray (https://correaa.github.io/boost-multi/multi/reference/boost/multi/const_suba...): similar issues to boost::multi::array_ref. I also noticed that some of the type aliases, e.g. move_iterator, are not used by any member function and make no sense for this type. Can they be removed from the documentation? boost::multi::cursor_t (https://correaa.github.io/boost-multi/multi/reference/boost/multi/cursor_t.h...): - The class itself has no description. - The documentation on strides (symbols `StridesType`, `strides_type`, `strides`, and `stride`) is missing entirely. Not even a short description. `StridesType` is passed in as a template parameter, but I have no idea what concrete type(s) would typically be passed in, where they are defined, or what their interface is. - The return type of operator[] is undocumented. - None of the type aliases have a description. - `base` has no description, although I think I can make out its purpose from its return type. boost::multi::dynamic_array (https://correaa.github.io/boost-multi/multi/reference/boost/multi/dynamic_ar...): similar issues to `boost::multi::array`. Also poorly named. Maybe `fixed_size_array`? boost::multi::elements_iterator_t (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elements_i...): it's a random access iterator that works like every other random access iterator, so I can excuse a certain sparseness in the documentation. That does not apply to the members that aren't part of the random access iterator interface, namely `base`, `current`, and `layout`. boost::multi::elements_range_t (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elements_r...): judging from its name, I would expect this to function as a non-owning range, roughly equivalent to `std::ranges::subrange<boost::multi::element_iterator_t>`. However, the exact semantics of the type are not documented. Specific concerns: - The constructor and operator= are marked as deleted on the main page. This is misleading: while the default implementations of these functions are deleted, there are other overloads available, including templated overloads that take the place of the deleted functions. - The semantics of operator= are ambiguous. Does it rebind the range or copy the contents of the right hand side? boost::multi::initializer_array (https://correaa.github.io/boost-multi/multi/reference/boost/multi/initialize...): the purpose and semantics of this class are a mystery. Document it properly if it's part of the public API; remove it if not. boost::multi::invoke_result_from_tuple (https://correaa.github.io/boost-multi/multi/reference/boost/multi/invoke_res...): I can guess it's purpose by clicking on the specialization (https://correaa.github.io/boost-multi/multi/reference/boost/multi/invoke_res...) and then clicking on the `type` member (https://correaa.github.io/boost-multi/multi/reference/boost/multi/invoke_res...). I shouldn't have to click twice to get this information. boost::multi::move_subarray (https://correaa.github.io/boost-multi/multi/reference/boost/multi/move_subar...): looking at the name, I guess this is a helper type for implementing move semantics for elements, possibly the return type of boost::multi::subarray::element_moved (although this is not documented). I shouldn't have to guess. boost::multi::restriction (https://correaa.github.io/boost-multi/multi/reference/boost/multi/restrictio...): almost completely undocumented. I'm guessing this is the return type of boost::multi::restrict, which is also undocumented. Yes, these members are mostly the same as those of every other array type. That doesn't excuse them being undocumented here. boost::multi::restriction_elements_iterator (https://correaa.github.io/boost-multi/multi/reference/boost/multi/restrictio...): similar concerns to boost::multi::elements_iterator_t above. In addition, there is a `system` type alias that not only has no description, but has a reference to the completely undocumented type `detail::function_system` in its documentation. There should be no references at all to the `detail` namespace in the documentation. boost::multi::restriction_elements_t (https://correaa.github.io/boost-multi/multi/reference/boost/multi/restrictio...): is this the restriction equivalent of boost::multi::elements_range_t? If so, why is it so much sparser than boost::multi::elements_range_t? Does it have any automatically generated functions (e.g. copy constructor or operator=), and if so, what are their semantics? boost::multi::restriction_iterator (https://correaa.github.io/boost-multi/multi/reference/boost/multi/restrictio...): it looks like a random access iterator. I can't tell if it actually is a random access iterator, i.e. if it meets the requirements of std::random_access_iterator. It looks like operator[] returns by value, although the actual return type is undocumented, and I can't make out what the `reference` type alias actually refers to. boost::multi::subarray (https://correaa.github.io/boost-multi/multi/reference/boost/multi/subarray.h...): pretty much the same concerns as boost::multi::array_ref. boost::multi::subarray_ptr (https://correaa.github.io/boost-multi/multi/reference/boost/multi/subarray_p...): with some hard competition, this type manages to be the worst documented type in the documentation. Congratulations! Here the documentation is limited to the types of the template arguments. It doesn't even have names for the template arguments, much less descriptions of what the template arguments are for, much less any members. Maybe this is a tag type without members? I wouldn't know; there's no description whatsoever of what this type is used for. boost::multi::unique_array (https://correaa.github.io/boost-multi/multi/reference/boost/multi/unique_arr...): this class seems to sit in the hierarchy between boost::multi::dynamic_array and boost::multi::array. It's not mentioned at all on https://correaa.github.io/boost-multi/multi/reference.html#ref_types, which makes me think that it may be an internal type not intended for public use. In which case, why document it at all? boost::multi::array_const_view (https://correaa.github.io/boost-multi/multi/reference/boost/multi/array_cons...): minimal documentation, but the synopsis says all that needs to be said. All that's missing is turning the text `array_ref` in the synopsis into a link. Wait, why is this a reference type? I don't know how this type is used internally in boost::multi or how users are intended to use it, but making it a reference without making this explicit in the type name seems very dangerous. Tracing dangling reference bugs is not fun. boost::multi::array_cref (https://correaa.github.io/boost-multi/multi/reference/boost/multi/array_cref...): similar to array_const_view, but the use of std::pointer_traits and std::decay_t makes it less pleasant to read. A short description would be appreciated. boost::multi::array_mref (https://correaa.github.io/boost-multi/multi/reference/boost/multi/array_mref...): see boost::multi::array_cref. boost::multi::array_view (https://correaa.github.io/boost-multi/multi/reference/boost/multi/array_view...): see boost::multi::array_const_view above. boost::multi::const_subarray_ptr (https://correaa.github.io/boost-multi/multi/reference/boost/multi/const_suba...): I found the missing template parameter names for boost::multi::subarray_ptr! boost::multi::inplace_array (https://correaa.github.io/boost-multi/multi/reference/boost/multi/inplace_ar...): it's a type alias to an undocumented type in a `detail` namespace. It must be documented as it it were a class, not a type alias. But at least the template parameter is documented. boost::multi::restriction_idl (https://correaa.github.io/boost-multi/multi/reference/boost/multi/restrictio...). No idea what 'idl' stands for, or what this type is used for, or if it should be a public type at all. boost::multi::apply_ (https://correaa.github.io/boost-multi/multi/reference/boost/multi/apply_.htm...): undocumented. Looks kind of like `std::apply`, expect it that it takes a parameter pack instead of a tuple as arguments, which makes me wonder who it even exists. Seriously, why does this exist? What does it do? Why does its name end with an underscore? boost::multi::base (https://correaa.github.io/boost-multi/multi/reference/boost/multi/base-0b.ht...): I can guess what it does, but I don't like having to guess. Isn't there already a member function with the same name and the same functionality? Why the free function? boost::multi::begin (https://correaa.github.io/boost-multi/multi/reference/boost/multi/begin.html): again, why the free function, and why not use std:begin instead? This is a serious question that I want the documentation to answer. boost::multi::cbegin (https://correaa.github.io/boost-multi/multi/reference/boost/multi/cbegin.htm...): see boost::multi::begin above. boost::multi::cend (https://correaa.github.io/boost-multi/multi/reference/boost/multi/cend.html): see boost::multi::begin above. boost::multi::data_elements (https://correaa.github.io/boost-multi/multi/reference/boost/multi/data_eleme...): not sure what this does. Oh wait, I think it just calls .elements().data() on its argument. Except that it's .elements().base() instead, because boost::multi::elements_range_t doesn't have a `data` member function but it does have a `base` member function with (apparently) the semantics of `std::vector::data()`. Did I guess right? boost::multi::decay (https://correaa.github.io/boost-multi/multi/reference/boost/multi/decay-00.h...): on the surface, this looks like another one of those free functions that just forward to the corresponding member functions. But why does it have two overloads that both take a `const_subarray const&` as argument, and where is the supposed return type, `decay_type`, documented? boost::multi::diagonal (https://correaa.github.io/boost-multi/multi/reference/boost/multi/diagonal.h...): another free function that forwards to a member function, or is it the member function that forwards to the free function? boost::multi::end (https://correaa.github.io/boost-multi/multi/reference/boost/multi/end.html): see boost::multi::begin above. boost::multi::extent (https://correaa.github.io/boost-multi/multi/reference/boost/multi/extent.htm...): just to be perfectly clear, the fact that I can guess that this just forwards to the corresponding member function in no way excuses the lack of description for this or any other function. I also want to see links to the actual member functions that this function calls. boost::multi::get_allocator (https://correaa.github.io/boost-multi/multi/reference/boost/multi/get_alloca...): this one is surprising, because one of the overloads takes a boost::multi::subarray, and I didn't think subarrays had allocators. Going back to the subarray documentation, I see that they have no allocator type alias, but they do have a `get_allocator` member function that returns a `default_allocator_type`, whatever that is. Looking further, `default_allocator_type` appears to be defined in the `boost::multi::const_subarray<T, 1, ElementPtr, Layout>::default_allocator_type` specialization, but not in any other subarray or const_subarray. So many questions. How can `boost::multi::subarray::get_allocator` compile if its return type doesn't exist? Why does a subarray, a non-allocating type, need an allocator? Why the free function? boost::multi::lexicographical_compare (https://correaa.github.io/boost-multi/multi/reference/boost/multi/lexicograp...): the name more or less describes what the function presumably does, but not the edge cases. In what order are elements compared? What happens if the two arrays being compared have different numbers of elements? The same number of elements but different shapes? Different rank? Can I use this function with restrictions? Does it use operator< or std::less, in case these differ? Is the function an alias to operator< itself? boost::multi::make_array_ref (https://correaa.github.io/boost-multi/multi/reference/boost/multi/make_array...): the overloads taking a specific (non-template-parameter) number of extents don't need to be documented separately. I'm not sure they need to exist at all. More to the point, I don't know what this function actually does. If I were to guess, I would guess that it creates an array_ref of the given extents, pointing to previous allocated memory. The `P` template parameter could stand for "pointer", so the `data` variable could be a pointer to the raw data, with the type of the data being `decltype(*data)`. But that's just a guess. None of this is clear from the documentation. I shouldn't have to guess. boost::multi::move (https://correaa.github.io/boost-multi/multi/reference/boost/multi/move-041.h...): why does this exist at all, when we already have std::move? Or does it do something confusingly different from std::move, without documenting the difference anywhere? boost::multi::operator+ (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_p...): yes, random access iterators require `operator+`. That information belongs with the actual iterator types. There is no need to include `operator+`, or most of the other operators, in the list of free functions. boost::multi::operator- (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_m...): see boost::multi::operator+. How is the list of free functions sorted anyway? It looks alphabetical, but some operators are under 'o' and others are at the very end of the list. boost::multi::operator->* (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_p...): this is an interesting function. It may even deserve a place among the free functions. It definitely deserves actual documentation. Speaking of `extents_t`, it doesn't seem to be defined anywhere. It's not included among the namespace-level symbols. `boost::multi::array::extents_type` points be to `layout_type::extents_type` (but without an actual link). `boost::multi::array::layout_type` points me to `array_ref<T, D, multi::allocator_traits<allocator_type>::pointer>::layout_type` (again without link). `boost::multi::array_ref::layout_type` points me to `subarray_base::layout_type`. `subarray_base` is not documented anywhere, but `boost::multi::subarray::layout` points to the `Layout` template parameter, which in turn defaults to `layout_t<D, std::pointer_traits<ElementPtr>::difference_type>>`. `layout_t`, in turn, is also not defined anywhere. boost::multi::operator/ (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_s...): well, the synopsis at least confirms that `multi::extents_t` exists. Unfortunately it tells me nothing what this function actually does. What does it mean to divide an iterator by an `extents_t`? boost::multi::operator^ (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_x...): the actual documentation is here: https://correaa.github.io/boost-multi/multi/tutorial.html#tutorial_restricti.... Link to that page, or copy the relevant information from it. Or better yet, do both. boost::multi::operator~ (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_b...): despite the insistence of the documentation that this is a bitwise negation operator, I have my doubts. Why does an array need a bitwise negation operator, and supposing it does, why is it not in the `elementwise` namespace? boost::multi::origin (https://correaa.github.io/boost-multi/multi/reference/boost/multi/origin-05....): why create a non-deprecated free function to forward to a deprecated member function? Or does this function do something different? boost::multi::ref (https://correaa.github.io/boost-multi/multi/reference/boost/multi/ref-050.ht...): I don't know why this exists or what it does. boost::multi::restricted (https://correaa.github.io/boost-multi/multi/reference/boost/multi/restricted...): no documentation aside from the parameter list, not even a return type. See operator^ above. boost::multi::rotated (https://correaa.github.io/boost-multi/multi/reference/boost/multi/rotated-06...): so the reason this exists as a free function is to allow nested C-style array as arguments. It still needs to document its return type and semantics. boost::multi::size (https://correaa.github.io/boost-multi/multi/reference/boost/multi/size-0fc.h...): does this do anything different from std::size? Why does it exist? boost::multi::sizes (https://correaa.github.io/boost-multi/multi/reference/boost/multi/sizes-00.h...): returns const_subarray::sizes_type, which is missing from the documentation entirely. Does `const_subarray::sizes_type` exist? How is it distinct from `boost::multi::extents_t`? How are either of them distinct from `std::array<size_type>`? Or is `sizes` not a plural at all, but short for `size signed`? boost::multi::static_array_cast (https://correaa.github.io/boost-multi/multi/reference/boost/multi/static_arr...): I have no idea what this does. It's a cast, but it takes multiple arguments? What does that even mean? boost::multi::stride (https://correaa.github.io/boost-multi/multi/reference/boost/multi/stride.htm...): it looks like another one of those free functions that forward to member functions, but to which member function? Which class in `boost::multi` has a `stride` member function? Is it `boost::multi::cursor_t`? Come to think of it, I have no idea what `boost::multi::cursor_t::stride` even does. I don't even know its return type, all I know is that it is const and doesn't take any arguments. boost::multi::swap (https://correaa.github.io/boost-multi/multi/reference/boost/multi/swap-059.h...): swap semantics between owning arrays are clear, swap semantics between array views less so. boost::multi::transposed (https://correaa.github.io/boost-multi/multi/reference/boost/multi/transposed...): there is really only one thing this function can do, so the only thing missing from the documentation is the return type. boost::multi::uninitialized_copy (https://correaa.github.io/boost-multi/multi/reference/boost/multi/uninitiali...): typo in the synopsis (which makes me wonder how this library even compiles; isn't the synopsis taken directly from the source code?). Also reference to the `detail` namespace in the synopsis. Also I don't know what this actually does. Copy into uninitialized memory, I guess, because it makes no sense to copy out from uninitialized memory. What does it do that `std::uninitialized_copy` can't do? boost::multi::unrotated (https://correaa.github.io/boost-multi/multi/reference/boost/multi/unrotated-...): see boost::multi::rotated, except this one for some reason doesn't work with C-style nested array? Why not? boost::multi::operator<< (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_l...): OK, it prints the array as text, but what does the result actually look like? boost::multi::operator== (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_e...): wait, no comparison between distinct array types (e.g. restriction and inplace_array)? boost::multi::operator!= (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_n...): see boost::multi::operator==. boost::multi::operator< (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_l...): ordering between arrays is not clearly defined; see boost::multi::lexicographical_compare. boost::multi::operator<= (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_l...): see boost::multi::operator<. boost::multi::operator> (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_g...): see boost::multi::operator<. boost::multi::operator>= (https://correaa.github.io/boost-multi/multi/reference/boost/multi/operator_g...): see boost::multi::operator<. boost::multi::force_element_trivial (https://correaa.github.io/boost-multi/multi/reference/boost/multi/force_elem...): I have no objections to the documentation here. boost::multi::force_element_trivial_default_construction (https://correaa.github.io/boost-multi/multi/reference/boost/multi/force_elem...): see boost::multi::force_element_trivial. boost::multi::force_element_trivial_destruction (https://correaa.github.io/boost-multi/multi/reference/boost/multi/force_elem...): see boost::multi::force_element_trivial. boost::multi::serialization_array_version (https://correaa.github.io/boost-multi/multi/reference/boost/multi/serializat...): the user doesn't need to know the actual value of the variable, but a sentence or two on its purpose and a link to https://correaa.github.io/boost-multi/multi/interop.html#interop_serializati... would be nice. boost::multi::elementwise::apply_bind_t (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): undocumented. No idea what it does. Probably the return type of a similiarly undocumented function. boost::multi::elementwise::default_zero_f (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::apply_bind_t. boost::multi::elementwise::identity_bind (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::apply_bind_t. boost::multi::elementwise::abs (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): this one is relatively well-documented, missing only the specific return type (which is probably something ugly that you'd never want to type out anyway, so no great loss). The problem is that the function is described to return an "array", and "array" is a sloppy concept. The library defines a whole bunch of "array" types which share a bunch of members, but which of these members are part of the "array" concept and which are specific to a particular concrete array type is never explicitly specified. There is also the name confusion between `boost::multi::array` the concrete type and the more general "array" concept. In practice, what boost::multi::elementwise::abs probably returns is a `boost::multi::restriction`, which a lot more specific and useful (the utter lack of documentation for `boost::multi::restriction` notwithstanding). boost::multi::elementwise::apply (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): I don't know what this does. I guess it's an elementwise version of std::apply. I guess it takes the function arguments from arrays of the same extents, creates another array of the same extents return the return values, and returns that array. I also guess that the function itself is not taken from an array, but passed directly. Is the returned array lazy or eager? Does it accept C-style arrays and std::array or just boost::multi arrays? Can I mix direct arguments with array arguments? On the good news, I think I may have solved the mystery of the underscore at the end of boost::multi::apply_. It's so that boost::multi::elementwise::apply can call it without namespace specifier and without recursively calling itself. I think. Maybe. boost::multi::elementwise::apply_front (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): another variety of elementwise std::apply. I have literally no idea what it does differently than boost::multi::elementwise::apply. What does "front" mean in this context? boost::multi::elementwise::exp (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::abs. boost::multi::elementwise::eye (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): I literally have no idea what this function does. An eye is a part of animal anatomy. I have never heard the word used in the context of a mathematical function. boost::multi::elementwise::log (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::abs. boost::multi::elementwise::map (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): I have, in fact heard of mapping a function over a (sequence of) array(s). It's what the Python `map` function (technically class) does. But Python's `map` takes an arbitrary sequence of arrays and boost::multi::elementwise::map takes exactly two. I'm confused. Does boost::multi::elementwise::map, in fact, do something completely different? boost::multi::elementwise::operator&& (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): I don't know what this does. Does it return an array of pairwise values, each with a value of `(a && b)`, where `a` and `b` come from corresponding input arrays? Lazily maybe? Or does it reduce all of these values to a single boolean? boost::multi::elementwise::operator* (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): fair enough, but see boost::multi::elementwise::abs for concerns about the return value. boost::multi::elementwise::operator+ (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::operator*. boost::multi::elementwise::operator- (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::operator*. boost::multi::elementwise::operator/ (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::operator*. boost::multi::elementwise::operator| (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): I would have expected this to continue the pattern set by boost::multi::elementwise::operator*, but instead of taking two arrays, it takes an array and a function. So what does it do? The description, "Bitwise disjunction operators", does not help. boost::multi::elementwise::operator|| (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): see boost::multi::elementwise::operator&&. boost::multi::elementwise::zeros (https://correaa.github.io/boost-multi/multi/reference/boost/multi/elementwis...): Let me guess, this creates a lazy array of zeros? On second though, don't let me guess. Tell me. boost::multi::pmr::array (https://correaa.github.io/boost-multi/multi/reference/boost/multi/pmr/array....) and boost::multi::pmr::dynamic_array (https://correaa.github.io/boost-multi/multi/reference/boost/multi/pmr/dynami...): no complaints. Non-documentation issues: Deleting the address-of operator for boost::multi::array and using operator& as a conversion operator instead is not acceptable. `taked` is still not a word in the English language. Use `taken` instead. If array::operator~ does the documentation says it does, why is it not in namespace elementwise? (The documentation says "Bitwise negation operators".) Why does boost::multi::cursor_t::operator[] not accept multiple arguments like boost::multi::array::operator[]? Why do operators [] and () not accept tuple-likes as arguments? I notice that the set of elementwise operators is rather small. Bitwise operators are missing. Unary minus is missing. Comparison operators are missing. Some of these would cause conflict with other operators in the library, others would not. Verdict: I would like to see a better multidimensional array library in Boost. I would even like to see *this* multidimensional array library in boost, if it were properly documented with some of the rough edges filed off. But I can barely see an improvement on the state of the documentation since the last review. I feel like I spent more time and effort on this review than the submitter did on the documentation. I also feel that I have barely scratched the surface in this review. I didn't even notice that major components (layout_t and extents_t) were missing from the documentation until halfway through. I don't want to outright reject a library that is already conditionally accepted, especially a library that meets a need I have, but I don't think the library substantially closer to ready for inclusion in Boost than the last time I saw it. I therefore vote to CONDITIONALLY ACCEPT the library, on the condition that every single one of my complaints is addressed, followed by another review. A summary of my most important requirements for the documentation: - If it's part of the public interface, it needs to be documented. - If it's not part of the public interface, it should not be documented. - Documentation must not refer to types that are not documented. That's effectively a broken link in the documentation, which is unacceptable. - If it's documented, it needs a human-written description in addition to the machine-generated synopsis. - Every parameter must be documented. - If it's of a concrete type that the library defines, it should link to the documentation of that type. - If it's a template type parameter, then the requirements of that type must be documented. - In addition to type, the semantic meaning of the parameter must be documented. - Every return value must be documented. - If it's of a concrete type that the library defines, it should link to that type. - If it's of an unspecified type that models a concept, the concept must be documented. - In addition to type, the semantic meaning of the return value must be documented. But read the full long list, because it contains a lot of specifics that I also feel are important. -- Rainer Deyke - rainerd@eldwood.com