411

Recently I've gotten suggestions to use span<T>'s in my code, or have seen some answers here on the site which use span's - supposedly some kind of container. But - I can't find anything like that in the C++17 standard library.

So what is this mysterious span<T>, and why (or when) is it a good idea to use it if it's non-standard?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 2
    `std::span` was proposed in 2017. It applies to C++17 or C++20. Also see [P0122R5, span: bounds-safe views for sequences of objects](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0122r5.pdf). Do you really want to target that language? It will be years before compilers catch up. – jww Jan 24 '18 at 00:29
  • 8
    @jww: span's are quite usable with C++11... as `gsl::span` rather than `std::span`. See also my answer below. – einpoklum Jan 24 '18 at 06:39
  • Also documented on cppreference.com: https://en.cppreference.com/w/cpp/container/span – Keith Thompson Mar 24 '20 at 19:18
  • 6
    @KeithThompson: Not in 2017 it wasn't... – einpoklum Mar 24 '20 at 21:02
  • 7
    @jww All compilers support std::span<> now in C++20 mode. And span is available from many 3rd party libs. You were right - it was years: 2 years to be precise. – Contango Jun 20 '20 at 07:43

4 Answers4

484

What is it?

A span<T> is:

  • A very lightweight abstraction of a contiguous sequence of values of type T somewhere in memory.
  • Basically a struct { T * ptr; std::size_t length; } with a bunch of convenience methods.
  • A non-owning type (i.e. a "reference-type" rather than a "value type"): It never allocates nor deallocates anything and does not keep smart pointers alive.

It was formerly known as an array_view and even earlier as array_ref.

When should I use it?

First, when not to use spans:

  • Don't use a span in code that could just take any pair of start & end iterators (like std::sort, std::find_if, std::copy and other templated functions from <algorithm>), and also not in code that takes an arbitrary range (see The C++20 ranges library for information about those). A span has stricter requirements than a pair of iterators or a range: element contiguity and presence of the elements in memory.
  • Don't use a span if you have a standard library container (or a Boost container etc.) which you know is the right fit for your code. spans are not intended to supplant existing containers.

Now for when to actually use a span:

Use span<T> (respectively, span<const T>) instead of a free-standing T* (respectively const T*) when the allocated length or size also matter. So, replace functions like:

void read_into(int* buffer, size_t buffer_size);

with:

void read_into(span<int> buffer);

Why should I use it? Why is it a good thing?

Oh, spans are awesome! Using a span...

  • means that you can work with that pointer+length / start+end pointer combination like you would with a fancy, pimped-out standard library container, e.g.:

    • for (auto& x : my_span) { /* do stuff */ }
    • std::find_if(my_span.cbegin(), my_span.cend(), some_predicate);
    • std::ranges::find_if(my_span, some_predicate); (in C++20)

    ... but with absolutely none of the overhead most container classes incur.

  • lets the compiler do more work for you sometimes. For example, this:

    int buffer[BUFFER_SIZE];
    read_into(buffer, BUFFER_SIZE);
    

    becomes this:

    int buffer[BUFFER_SIZE];
    read_into(buffer);
    

    ... which will do what you would want it to do. See also Guideline P.5.

  • is the reasonable alternative to passing const vector<T>& to functions when you expect your data to be contiguous in memory. No more getting scolded by high-and-mighty C++ gurus!

  • facilitates static analysis, so the compiler might be able to help you catch silly bugs.

  • allows for debug-compilation instrumentation for runtime bounds-checking (i.e. span's methods will have some bounds-checking code within #ifndef NDEBUG ... #endif)

  • indicates that your code (that's using the span) doesn't own the pointed-to memory.

There's even more motivation for using spans, which you could find in the C++ core guidelines - but you catch the drift.

But is it in the standard library?

edit: Yes, std::span was added to C++ with the C++20 version of the language!

Why only in C++20? Well, While the idea is not new - its current form was conceived in conjunction with the C++ core guidelines project, which only started taking shape in 2015. So it took a while.

So how do I use it if I'm writing C++17 or earlier?

It's part of the Core Guidelines's Support Library (GSL). Implementations:

  • Microsoft / Neil Macintosh's GSL contains a standalone implementation: gsl/span
  • GSL-Lite is a single-header implementation of the whole GSL (it's not that big, don't worry), including span<T>.

The GSL implementation does generally assume a platform that implements C++14 support [12]. These alternative single-header implementations do not depend on GSL facilities:

Note that these different span implementations have some differences in what methods/support functions they come with; and they may also differ somewhat from the version adopted into the standard library in C++20.


Further reading: You can find all the details and design considerations in the final official proposal before C++17, P0122R7: span: bounds-safe views for sequences of objects by Neal Macintosh and Stephan J. Lavavej. It's a bit long though. Also, in C++20, the span comparison semantics changed (following this short paper by Tony van Eerd).

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 2
    Wouldn't `read_into(int* from, int* to)` be way more in line with the usual (iterator based) approach of the standard library? – Daniel Jour Aug 17 '17 at 10:44
  • @DanielJour: I wanted a minimalistic example. Both your and my variant of the functions would probably not be something you would actually put in a library anyway. Also, note that with your variant, it's not possible to know how much you need to read, so maybe you mean `read_into(int* from, int* to, size_t n)`? That's mentioned in the Core Guidelines document as a "bad example" actually. – einpoklum Aug 17 '17 at 11:03
  • @einpoklum oh, no, that's not what I meant. Different take: `read_into(int* begin, int* end)` – Daniel Jour Aug 17 '17 at 12:25
  • @DanielJour: Ah well, the thing is, with a `span`, you don't know/don't care whether internally it has `int* begin; size_t length` or `int* begin; int* end;` So I don't think it matters all that much. – einpoklum Aug 17 '17 at 12:32
  • 6
    It would make more sense to standardize a general range (supporting iterator+sentinel and iterator+length, maybe even iterator+sentinel+length) and make span a simple typedef. Because, you know, that's more generic. – Deduplicator Aug 17 '17 at 12:47
  • Pity that they didn't standardize the representation, so it could be used for interop between different languages. – CodesInChaos Aug 17 '17 at 12:50
  • 3
    @Deduplicator: Ranges are coming to C++, but the current proposal (by Eric Niebler) requires support for Concepts. So not before C++20. – einpoklum Aug 17 '17 at 12:52
  • 2
    Can you explain how span can know the size of an array while it is constructed just by the array pointer alone ? Is it due to span can read the bytes next to the pointer to get the size info (I guess these bytes are also allocated by `new` or `malloc`, so they can correctly `delete` it later)? I can not find any article about this, and hint is appreciated. Thanks. – Hải Phạm Lê Aug 22 '17 at 13:20
  • 8
    @HảiPhạmLê: Arrays don't immediately decay into pointers. try doing `std::cout << sizeof(buffer) << '\n'` and you'll see you get 100 sizeof(int)'s. – einpoklum Aug 23 '17 at 07:59
  • 1
    @einpoklum : I see, yes, you're right. Is it true that compiler can tell the size of buffer since it's known at compile time ? `sizeof` is also compile time function. But, what about memory allocated dynamically by `new` or `malloc`? Can `span` work with them ? – Hải Phạm Lê Aug 23 '17 at 09:08
  • 1
    @HảiPhạmLê: It can tell the size of the buffer because buffer is defined as a sized array. That has nothing to do with compile-time vs. run-time. Read the answers to [this question](https://stackoverflow.com/questions/1461432/what-is-array-decaying) here on SO. – einpoklum Aug 23 '17 at 09:13
  • What are the advantages/disadvantages compared to [std::array](https://en.cppreference.com/w/cpp/container/array)? – Jim Nov 07 '18 at 17:55
  • 7
    @Jim `std::array` is a container, it owns the values. `span` is non-owning – Caleth Dec 04 '18 at 14:18
  • 4
    @Jim: `std::array` is a completely different beast. Its length is fixed at compile-time and it's a value-type rather than a reference-type, as Caleth explained. – einpoklum Dec 04 '18 at 14:56
  • Example around `read_into(buffer);` is the key issue I am having here. Native array reference, very successfully kills the 'span' idea in that scenario. It is "fundamental vocabulary type" in the same way std::span might be. I "need" this clearly mentioned in 'span' jubilation's. – Chef Gladiator Mar 27 '19 at 10:45
  • ards set example – quantdev Apr 14 '19 at 01:16
  • Tristan Brindle's [implementation of `span`](https://github.com/tcbrindle/span) has the benefit to be only a single header-file with few lines of code, supports *C++11 or later* and has no dependencies to other GSL facilities. – user5534993 Aug 18 '19 at 12:51
  • @user5534993: How is this comment improving on what I've already written? – einpoklum Aug 18 '19 at 13:02
  • The biggest advantage over an STL container that could serve as a quasi-`span` (like `array` or `vector`), @Jim, is that you don't need to awkwardly turn it into a reference type by storing a pile of pointers or `reference_wrapper`s to the data you'd want to view. – Justin Time - Reinstate Monica Aug 18 '19 at 17:57
  • So basically, `span` is like `string_view`, but works with any type, not only with `char`, right? – Ruslan Aug 30 '19 at 22:16
  • 1
    @Ruslan: There are similarities between them - but they are not the same. There are significant differences, at least in terms of their available methods. – einpoklum Aug 31 '19 at 14:14
  • "*a bunch of convenience methods*" is a rather disparaging term for **a standard collection interface**, don't you think? – Toby Speight Mar 03 '20 at 17:48
  • @einpoklum, please update the answer to explain in detail how `span` differs from `std::array`, and which one is better for what, why. – Gabriel Staples Apr 14 '20 at 18:08
  • 1
    @GabrielStaples: I will not. There is no reason to focus on `std::array` here, as opposed to any other specific container. Also, if you know `std::array` at all, then the answer does explain how they differ. IMHO. – einpoklum Apr 14 '20 at 18:51
  • 1
    It's not clear enough in a single pass to someone who's never heard of a span before. This is sufficient: please replace your 2nd bullet with this: "- Basically a **single** `struct { T * ptr; std::size_t length; }` with a bunch of convenience methods. (Notice this is distinctly different from `std::array<>` because a `span` enables convenience accessor methods comparable to `std::array` via a _pointer to type `T`_ and length of type `T`, whereas `std::array` is an actual container which holds one or more _values_ of type `T`.) ". Done. That's all I'm asking for. This helps so much. – Gabriel Staples Apr 14 '20 at 19:12
  • @GabrielStaples: There is no reason to focus on std::array rather than, say `std::vector`. – einpoklum Apr 14 '20 at 19:43
  • _"reasonable alternative to passing const vector& to functions when you expect your data to be contiguous in memory"_. Could somebody expand? Aren't vectors contiguous in memory? – luizfls Apr 26 '20 at 03:15
  • 1
    @luizfls: They are. But if that's what your function needs - don't insist on the input being an `std::vector` - any contiguous sequence of memory will do, and the span is just the container to represent it. – einpoklum Apr 26 '20 at 06:09
  • 1
    first you say to not use it with `std::find_if` and then you use it yourself... I feel like a different wording is needed – Noone AtAll Aug 27 '20 at 16:43
  • Specifically about `cstring_span<>`, this specific span doesn't store any character data, correct? So hypothetically, if I had a `cstring_span<>` that was, e.g., allocated from `std::string::c_str()`, it would also have the same lifetime that the `char*` from `c_str` would have, correct? What value does a `cstring_span` add over just working with the `char*` or `std::string`? – jrh Oct 21 '20 at 20:25
  • @jrh: Thanks for noticing the typo. Anyway - I don't know about a `cstring_span`; that's not in the standard library and not in my answer. But generally - spans don't store any data. And, yes, its lifetime is the same as the pointer. "What value does it add" <- It has the length, on the one hand, and it's a cheap simple structure which doesn't own any memory, on the other. – einpoklum Oct 21 '20 at 20:29
  • @einpoklum ah, I see, I wasn't aware that it was non-standard. I noticed it was in an old version of GSL, I wasn't sure where it came from. Thanks! – jrh Oct 21 '20 at 20:35
  • 1
    “Don’t use it in code that could just take any pair of start & end iterators” ― Why? Isn’t `std::span` meant to get rid of pairs? – Константин Ван Dec 31 '20 at 22:57
  • 2
    @КонстантинВан: No... pair-of-iterators is much more general. For example: `std::list`'s beginning and end are two iterators, but the elements are not consecutive in memory, so it doesn't fit a span. – einpoklum Dec 31 '20 at 23:11
  • 1
    @einpoklum: While “Don’t use it in code that could just take any pair of start & end iterators” isn't wrong, it's also not completely correct unless it points the reader to Ranges (`` header). – Ben Voigt Jul 14 '22 at 15:37
  • @BenVoigt: The answer predates C++20, when there was no such thing. I suppose I might want to rethink that point. – einpoklum Jul 14 '22 at 17:43
  • @einpoklum: I considered that possibility but the answer mentions C++20 quite a few times. It's not like Ranges are proposed more recently than span either. – Ben Voigt Jul 14 '22 at 17:53
  • @einpoklum ***Don't use a span in code that could just take any pair of start & end iterators (like std::sort, std::find_if, std::copy and other templated functions from )*** Why?Could you please explain that in more detail for me? – John Oct 13 '22 at 09:34
  • Can I summarize that std::span is the "dynamic" version of std::array ? – walkerlala Jun 26 '23 at 02:41
  • @walkerlala: No, because it is absolutely not that. `std::array` owns the data; `std::span` does not. – einpoklum Jun 26 '23 at 07:05
  • @einsupportsModeratorStrike Yes you are right with that. I think std::span means "array ref", and should be renamed to ArrayRef, as LLVM does https://llvm.org/doxygen/classllvm_1_1ArrayRef.html – walkerlala Jun 26 '23 at 07:53
  • @walkerlala: If you'll read the first section of my answer, you'll note it used to be named that. – einpoklum Jun 26 '23 at 07:54
  • @einsupportsModeratorStrike Do you know why the name was dropped ? – walkerlala Jun 26 '23 at 08:48
  • @walkerlala: No, you'll have to ask committee members. I suspect it may be due to a desire to avoid an overly close association with `std::array` but who knows. – einpoklum Jun 26 '23 at 11:11
50

A span<T> is this:

template <typename T>
struct span
{
    T * ptr_to_array;   // pointer to a contiguous C-style array of data
                        // (which memory is NOT allocated nor deallocated 
                        // nor in any way managed by the span)
    std::size_t length; // number of elements of type `T` in the array

    // Plus a bunch of constructors and convenience accessor methods here
}

It is a light-weight wrapper around a C-style array, preferred by C++ developers whenever they are using C libraries and want to wrap them with a C++-style data container for "type safety" and "C++-ishness" and "feelgoodery". :)

Note: I call the struct container defined above, known as a span, a "light-weight wrapper around a C-style array" because it points to a contiguous piece of memory, such as a C-style array, and wraps it with accessor methods and the array's size. This is what I mean by "light-weight wrapper": it is a wrapper around a pointer and a length variable, plus functions.

Unlike a std::vector<> and other C++ standard containers, however, which may also just have fixed class sizes and contain pointers which point to their storage memory, a span does not own the memory it points to, and will never delete it nor resize it nor allocate new memory automatically. Again, a container like a vector owns the memory it points to, and will manage (allocate, reallocate, etc.) it, but a span does not own the memory it points to, and therefore will not manage it.


Going further:

@einpoklum does a pretty good job of introducing what a span is in his answer here. However, even after reading his answer, it is easy for someone new to spans to still have a sequence of stream-of-thought questions which aren't fully answered, such as the following:

  1. How is a span different from a C array? Why not just use one of those? It seems like it's just one of those with the size known as well...
  2. Wait, that sounds like a std::array, how is a span different from that?
  3. Oh, that reminds me, isn't a std::vector like a std::array too?
  4. I'm so confused. :( What's a span?

So, here's some additional clarity on that:

DIRECT QUOTE OF HIS ANSWER--WITH MY ADDITIONS and parenthetical comments IN BOLD and my emphasis in italics:

What is it?

A span<T> is:

  • A very lightweight abstraction of a contiguous sequence of values of type T somewhere in memory.
  • Basically a single struct { T * ptr; std::size_t length; } with a bunch of convenience methods. (Notice this is distinctly different from std::array<> because a span enables convenience accessor methods, comparable to std::array, via a pointer to type T and length (number of elements) of type T, whereas std::array is an actual container which holds one or more values of type T.)
  • A non-owning type (i.e. a "reference-type" rather than a "value type"): It never allocates nor deallocates anything and does not keep smart pointers alive.

It was formerly known as an array_view and even earlier as array_ref.

Those bold parts are critical to one's understanding, so don't miss them or misread them! A span is NOT a C-array of structs, nor is it a struct of a C-array of type T plus the length of the array (this would be essentially what the std::array container is), NOR is it a C-array of structs of pointers to type T plus the length, but rather it is a single struct containing one single pointer to type T, and the length, which is the number of elements (of type T) in the contiguous memory block that the pointer to type T points to! In this way, the only overhead you've added by using a span are the variables to store the pointer and length, and any convenience accessor functions you use which the span provides.

This is UNLIKE a std::array<> because the std::array<> actually allocates memory for the entire contiguous block, and it is UNLIKE std::vector<> because a std::vector is basically just a std::array that also does dynamic growing (usually doubling in size) each time it fills up and you try to add something else to it. A std::array is fixed in size, and a span doesn't even manage the memory of the block it points to, it just points to the block of memory, knows how long the block of memory is, knows what data type is in a C-array in the memory, and provides convenience accessor functions to work with the elements in that contiguous memory.

It is part of the C++ standard:

std::span is part of the C++ standard as of C++20. You can read its documentation here: https://en.cppreference.com/w/cpp/container/span. To see how to use Google's absl::Span<T>(array, length) in C++11 or later today, see below.

Summary Descriptions, and Key References:

  1. std::span<T, Extent> (Extent = "the number of elements in the sequence, or std::dynamic_extent if dynamic". A span just points to memory and makes it easy to access, but does NOT manage it!):
  2. https://en.cppreference.com/w/cpp/container/span
  3. std::array<T, N> (notice it has a fixed size N!):
  4. https://en.cppreference.com/w/cpp/container/array
  5. http://www.cplusplus.com/reference/array/array/
  6. std::vector<T> (automatically dynamically grows in size as necessary):
  7. https://en.cppreference.com/w/cpp/container/vector
  8. http://www.cplusplus.com/reference/vector/vector/

How Can I Use span in C++11 or later today?

Google has open-sourced their internal C++11 libraries in the form of their "Abseil" library. This library is intended to provide C++14 to C++20 and beyond features which work in C++11 and later, so that you can use tomorrow's features, today. They say:

Compatibility with the C++ Standard

Google has developed many abstractions that either match or closely match features incorporated into C++14, C++17, and beyond. Using the Abseil versions of these abstractions allows you to access these features now, even if your code is not yet ready for life in a post C++11 world.

Here are some key resources and links:

  1. Main site: https://abseil.io/
  2. https://abseil.io/docs/cpp/
  3. GitHub repository: https://github.com/abseil/abseil-cpp
  4. span.h header, and absl::Span<T>(array, length) template class: https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L153

Other references:

  1. Struct with template variables in C++
  2. Wikipedia: C++ classes
  3. default visibility of C++ class/struct members

Related:

  1. [another one of my answers on templates and spans] How to make span of spans
Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
  • 5
    I would really not recommend using all of abseil to get a span class. – einpoklum Aug 28 '20 at 10:19
  • got it. The biggest advantage is light-weight. – yushang Jul 01 '21 at 12:33
  • 1
    @yushang, from a C++ developer's point-of-view, I think the biggest advantage isn't "light-weight", but is rather: "wraps around already-existing C arrays", so that no copying is necessary, and you now have a wrapper around a container which holds its size inside of it, unlike C arrays, which don't know nor carry around information about their own size. As an embedded developer, with more experience in C than in C++, myself, however, I'd generally prefer to just use raw C arrays anyway, over a span. – Gabriel Staples Aug 08 '21 at 22:46
  • `void array_operator ( const size_t count_, char arr [ static count_ ] );` that is standard C. In there one has full array info. Plus `arr` must have min `count_` elements. Context is this discussion not "C is better" rant. – Chef Gladiator Aug 12 '21 at 18:10
  • Also, this bothers me too: https://developercommunity.visualstudio.com/t/std::span-is-not-zero-cost-because-of-th/1429284 – Chef Gladiator Aug 12 '21 at 18:30
  • 1
    It is not a wrapper to a C-style array; `std::array` is a wrapper to a C-style array. `std::span` is a *reference* to a contiguous sequence, such as a C-style array. – John McFarlane Nov 02 '21 at 14:05
  • @JohnMcFarlane, I see what you're saying but you're just artificially limiting the word "wrapper" to mean "cannot contain just a pointer or reference, and length." That's unnecessarily narrow. The first thing I did was present a possible span implementation at the top of my answer, in code, and with comments, which agrees with what you said. Then, I called that struct container, known as a span, a "light-weight wrapper around a C-style array" because it points to a contiguous piece of memory and wraps it with accessor methods and the array's size. I call that a "light-weight wrapper." – Gabriel Staples Nov 02 '21 at 16:28
  • @GabrielStaples `span` is certainly not a container. It does not own the pointee or control its lifetime. OTOH, it does owns a pointer and control that pointer's lifetime. So if `span` is a wrapper, then it's a wrapper around a pointer. – John McFarlane Nov 02 '21 at 19:23
  • @JohnMcFarlane, agreed. A `span` is a wrapper around a pointer and a length variable (plus functions). That's what I mean by "light-weight". – Gabriel Staples Nov 02 '21 at 19:51
4

The answer provided by Einpoklum is great but I had to dive deep into the comments section to understand one specific detail so this is meant as an extension to clarify that detail.

First, when not to use it:

Don't use it in code that could just take any pair of start & end iterators, like std::sort, std::find_if, std::copy and all of those super-generic templated functions. Don't use it if you have a standard library container (or a Boost container etc.) which you know is the right fit for your code. It's not intended to supplant any of them.

Any pair of start & end iterators as opposed to start and end pointers of continuous storage.

As someone who rarely gets into contact with the interior of iterators it escaped me during my reading of the answer that iterators could iterate over a linked list, which simple pointers(and a span) could not.

Tolar
  • 61
  • 4
  • `span`s are constructible from contiguous iterators, which are not necessarily pointers. `vector::iterator` is contiguous, but not a pointer -- for example. The comment you quoted effectively boils down to "use the right tool for the job"; if you are writing an algorithm/utility over an arbitrary sequence, don't try to erase it into a `span` since this prevents any normal container from being used. However, if you want to have a container that represents non-owning contiguous data, `span` is likely the right call. – Human-Compiler Jul 06 '22 at 01:20
  • iterators could iterate over.... a linked-list, a red-black tree, a hashmap (all of which have implementations in the C++ Standard Library), and anything else including third-party exotic containers. – Ben Voigt Jul 14 '22 at 15:44
  • I agree with what you two wrote. It seems to be a rephrasing/repetition of the very fact that I tried summarizing/highlighting here. – Tolar Jul 21 '22 at 15:25
  • 1
    This answer inspired me to expand mine somewhat. So, +1 for it, but I hope now the point you are making is obvious enough when reading my answer. – einpoklum Sep 10 '22 at 16:32
  • I think it is obvious now, but I can no longer proof-read, because now I know and it's a detail that is hard to unlearn so I wouldn't know if earlier me would repeat my oversight. I'll leave it to others to decide if my answer should be deleted. – Tolar Sep 27 '22 at 09:01
0

A span is (or rather: has) a pointer to data not owned by that span. In effect you can do ranged operations on a span that affect someone else's data.

This means you can write things like an in-place quicksort:

void qs( span<T> data ) {
   split(data);
   qs( span{ data+0,sizeoffirst } );
   qs( span{ data+sizeoffirst,sizeofsecond } );

or any number of Lapack-style linear algebra functions by recursion or parallelism.

Victor Eijkhout
  • 5,088
  • 2
  • 22
  • 23
  • 1
    This is more of a comment. – einpoklum Aug 10 '23 at 21:14
  • After edit, is my about "when should I use it" clearer? – Victor Eijkhout Aug 10 '23 at 21:47
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/low-quality-posts/34826238) – SwissCodeMen Aug 14 '23 at 19:19
  • @SwissCodeMen I have no idea what you're telling me about critique or clarification. I'm not doing either. Also: are you a C++ expert? I'm giving a usage scenario when it can be used, which answers the question. – Victor Eijkhout Aug 14 '23 at 19:36
  • @SwissCodeMen It also seems that you're the only one out of 3 reviewers that has a problem with this answer. – Victor Eijkhout Aug 14 '23 at 19:38
  • I don‘t have a problem with your answer, I just can‘t see any real new knowledge compared to the existing answers. In addition, it’s allowed to have different views, and if two other reviewers have different opinions then mine, that's fine and your answer stands. I struggle with answers that don’t bring new knowledge to light but only reinforce/repeat existing knowledge. You could make your answer unique by coding out examples of your mentioned recursion or parallelism, thus covering `span` in that regard and isn‘t answered in any other answers. – SwissCodeMen Aug 14 '23 at 21:31
  • @SwissCodeMen I don't see my point about operating on (non-owned) *sub-arrays* covered anywhere. The important application area of linear algebra is not mentioned anywhere. For application scientists that is much much much more important than the fact that it's something light-weight. So the "when should I use one" is covered only in my answer: if you do linear algebra, or other operations (such as in-place sorting) where you want a non-owned sub-array. And that is unique to my answer. – Victor Eijkhout Aug 15 '23 at 10:18