Allow array as function return value

416 views
Skip to first unread message

will wray

unread,
Feb 18, 2019, 10:30:53 AM2/18/19
to ISO C++ Standard - Future Proposals
With C++17's value-category simplification, array value return from functions could now be allowed.

Has this been discussed before here or elsewhere? Links?

With array return allowed, struct wrappers like std::array are not necessary:

  char abc1D()[3] { return {'a','b','c'}; } // array return with brace-init

Ties in nicely with structured bindings for simple packing & unpacking of multiple same-type returns:

  auto [a,b,c] = abc1D();  // structured binding to elements of returned array

The structured binding provides the lifetime extension (and can provide implicit array copy too).
Otherwise, remember to bind the returned array to a reference:

  auto& abc = abc1D();

The danger, of course, is that attempts to copy fail because of array decay to pointer
which applies all too eagerly on assignments:

  auto dangle = abc();     // dangle is a char* to an array that just expired
  char abc_bcpy[3]{abc()}; // error: invalid conversion from 'char*' to 'char'
  char abc_pcpy[3](abc()); // with P0960, paren-init for aggregate, same as above

Manuel Bergler

unread,
Feb 18, 2019, 10:49:31 AM2/18/19
to std-pr...@isocpp.org

Am Mo., 18. Feb. 2019 um 16:30 Uhr schrieb will wray <wjw...@gmail.com>:
[...]

With array return allowed, struct wrappers like std::array are not necessary:
 
What's wrong with std::array as a function return type? Both returning with brace-init and structured bindings work for std::array.
 

will wray

unread,
Feb 18, 2019, 11:24:37 AM2/18/19
to ISO C++ Standard - Future Proposals
std::array is long in the tooth as an early C++11 demo class.

std::array hasn't proved itself as a 'vocabulary' type for API usage -
spans and ranges supersede and they operate fine with built-in array.

std::array does not 'roundtrip' the wrapped array type; data() returns a pointer.
std::array tuple-access customization for structured binding access trumps the regular
aggregate structured binding access which would have given direct 'roundtrip' access...
std::array is awkward to use for multidimensional arrays.
std::array CTAD guides added for 17 only give 'all or none' deduction - you can't provide
just the type and deduce size - function's deducing built-in array are more flexible.

std::array doesn't have C-linkage.
std::array may add end-padding (?).

Built-in array, despite the danger, is a simple language-level solution.
Built-in array has std::swap specialization... 

Joel FALCOU

unread,
Feb 18, 2019, 11:33:19 AM2/18/19
to std-pr...@isocpp.org

On 18/02/2019 17:24, will wray wrote:
> std::array is long in the tooth as an early C++11 demo class.

Wrong - it's perfectly simple for entry level. Source, I teach C++ since
10 years and array has never been a problem
C array always have been.


> std::array hasn't proved itself as a 'vocabulary' type for API usage -
> spans and ranges supersede and they operate fine with built-in array.

std:::array is a data owner, nothing comparable to span

> std::array does not 'roundtrip' the wrapped array type; data() returns
> a pointer.

And ?

> std::array is awkward to use for multidimensional arrays.

Opinion, not fact

> std::array CTAD guides added for 17 only give 'all or none' deduction
> - you can't provide
> just the type and deduce size - function's deducing built-in array are
> more flexible.
Make a proposal and amend them.

builtin array are non copiable, are not object etc...
Is the game of give opinions instead of facts done or ?

C style arrays must disappear as they have no value over std::array

Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

will wray

unread,
Feb 19, 2019, 10:52:40 AM2/19/19
to ISO C++ Standard - Future Proposals
(Trying one more time - previous attempts went to the google groups spam filter)

C-array is an atomic aggregate - a pure crystal condensate of one atom type.

This thread is to discuss improved language support for C-array via array return.

(It is not about addressing std::array shortcomings.
 It is not an either / or. 
 C-array and std::array are different tools for different tasks.)
The fact that array return is now technically feasible shows how far C++ language
specification has risen above its C roots.
What was impossible for forty years is now possible.
Raw array is analogous to raw pointer.
We've outgrown the urge to wrap all pointers - that's not so smart.
Raw pointers have been rehabilitated as the right tool for low level code.
Raw arrays deserve to be rehabilitated, with a little language level love.

On Monday, February 18, 2019 at 11:33:19 AM UTC-5, Joel Falcou wrote:
C style arrays must disappear as they have no value over std::array 

(Eh? Trollish joke?)
C-array is essential to implement std::array - it can't and won't disappear.

std::array is a molecular aggregate, an abstract compound
'compound': make (something bad) worse; intensify the negative aspects of.

Jake Arkinstall

unread,
Feb 19, 2019, 11:30:47 AM2/19/19
to std-pr...@isocpp.org
On Tue, 19 Feb 2019, 15:52 will wray <wjw...@gmail.com wrote:
(Trying one more time - previous attempts went to the google groups spam filter)

C-array is an atomic aggregate - a pure crystal condensate of one atom type.

This thread is to discuss improved language support for C-array via array return.

(It is not about addressing std::array shortcomings.
 It is not an either / or. 
 C-array and std::array are different tools for different tasks.)
The fact that array return is now technically feasible shows how far C++ language
specification has risen above its C roots.
What was impossible for forty years is now possible.
Raw array is analogous to raw pointer.
We've outgrown the urge to wrap all pointers - that's not so smart.
Raw pointers have been rehabilitated as the right tool for low level code.
Raw arrays deserve to be rehabilitated, with a little language level love.

I'm not so sure on that. std::array gives the compiler the knowledge of the size so that the user doesn't have to pass it around manually, but in a compiled executable I don't see any difference except for removal of jump instructions in the std::array case thanks to loop unrolling.

Im definitely against any notion of removing raw arrays from the language (because it is nonsensical), but I also never use them explicitly unless I'm doing unmentionable casty and c-stringy things in low latency settings - and even then I'm doing it via std::array.data().
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

Thiago Macieira

unread,
Feb 19, 2019, 10:34:34 PM2/19/19
to std-pr...@isocpp.org
On Tuesday, 19 February 2019 07:52:40 PST will wray wrote:
> > The fact that array return is now technically feasible shows how far C++
>
> language
> specification has risen above its C roots.
> What was impossible for forty years is now possible.

C++ will not diverge from C here, since that would be a behaviour difference.
Currently returning arrays is a compiler error in both languages, so it's
possible for C++ to define the behaviour, but only if C decides forever to use
the same behaviour or keep it a compilation error.

Conclusion: you must convince WG14 first, or get their word that they will not
define this behaviour.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel System Software Products



Nicol Bolas

unread,
Feb 19, 2019, 10:55:20 PM2/19/19
to ISO C++ Standard - Future Proposals
On Tuesday, February 19, 2019 at 10:52:40 AM UTC-5, will wray wrote:
(Trying one more time - previous attempts went to the google groups spam filter)

C-array is an atomic aggregate - a pure crystal condensate of one atom type.

This thread is to discuss improved language support for C-array via array return.

(It is not about addressing std::array shortcomings.
 It is not an either / or. 
 C-array and std::array are different tools for different tasks.)

The general argument against your proposal is that they should not be viewed that way. That `std::array` ought to be viewed as fixed version of C-arrays, and we should endeavor to make `std::array` more palatable in places where it is problematic, rather than trying to make C-arrays more functional.

It's a conflict of world-views. You see C-arrays as an inherent good that should be brought up to parity with other language features. Others see C-arrays as a necessary evil which should be marginalized as much as possible by providing alternatives (`std::array`, `std::span`, etc) that work more naturally with C++'s rules.

From a more objective POV, my feeling is that `std::array` really only has two significant flaws relative to to C arrays: not being able to omit the size of an array while still specifying the type (which is a matter of CTAD), and the general verbosity of multi-dimensional arrays. The fact that `data()` returns a pointer is irrelevant in a world where `std::span` can be used for taking references to sized arrays. `std::array<T,N>` is convertible to a `std::span<T, N>` or to a dynamically sized span; that's good enough.

On a personal level, the biggest problem I have with increasing the use of C-arrays is syntactic. Just look at one of your examples:


char abc1D()[3] { return {'a','b','c'}; }

If the `[3]` applies to the `char` as part of the return type, why is it on the other side of the function name? The return type should be either on the left or the right; it shouldn't be scattered between them. My first thought was that you were somehow creating an array of functions, not a function that returns an array.

By contrast:

std::array<char, 3> abc1D();

That looks like a regular function returning a regular type. The entirety of the return type is in one place in the function declaration. It may be more verbose than your version, but that regularity and consistency has its place.

Contrast this to GLSL, where arrays can in fact be return values. In that syntax, the array size is visually (or can be written as) part of the type. You can write `float[30] array`, rather than `float array[30]` (though the latter works too). So when you return an array, you do `float[10] func_name(...)`.

GLSL of course had the advantage that pointers don't exist, so there are no decay-to-pointer rules...

Also, there is a problem of a lack of consistency. If you can return an array by value, and you can declare a variable that is an array which receives that array by value... why can't you pass an array by value to a function? Because `void func(char arr[3])` still just takes a pointer, not an array. And you can't fix that, since it would be a breaking change. By contrast, `void func(std::span<char, 3> arr)` is not a lie; you cannot just pass a pointer to that.

Encouraging the use of C-arrays in the way you suggest is kind of a lie. Right now, arrays are not regular types; they are objects, but they're not regular types. Being able to return them by value suggests that they are value types, but it only makes them value types in one case.

Also, I'm curious as to what it is exactly about C++17's value category system that makes your proposal possible where it was not possible before.

will wray

unread,
Feb 20, 2019, 11:29:02 AM2/20/19
to ISO C++ Standard - Future Proposals
Thanks Nicol; an eloquent response addressing the topic.

While not quite an inherent good, C-array is our closest model of contiguous memory,
which close mapping was surely a contributor to the success of C and then C++.

On Tuesday, February 19, 2019 at 10:55:20 PM UTC-5, Nicol Bolas wrote:
...I'm curious as to what it is exactly about C++17's value category system that makes your proposal possible where it was not possible before.

I was referring to P0135 "Guaranteed copy elision through simplified value categories".
See e.g. Barry's blog Value Categories in C++17; 'copy' initialization of a non-movable type
is the usual example (some say 'elison' is not the right word - 'evasion' may be more accurate).
I guess that array return could have been possible as a special case without this.

This proposed change allows a callee to allocate and return static array storage in the caller,
unwrapped - array is already an aggregate, no need to conglomerate it.

Syntactically, inside-out "declaration resembles usage" is a stumbling block,
though it is now nicely addressed with a using declaration;
template <typename T, size_t N> using carray = T[N];

Again, raw arrays, like raw pointers, are for low level code that calls for language expertise.
Poor syntax here could be seen as a feature as it puts off those who should not use it.

Ritchie calls out array-pointer relationship and declaration syntax as C's main issues
in the Critque section of The Development of the C Language,
which goes on to give several paragraphs on array:

The other characteristic feature of C, its treatment of arrays, is more suspect on practical grounds, though it also has real virtues.
...
C's treatment of arrays in general (not just strings) has unfortunate implications both for optimization and for future extensions. The prevalence of pointers in C programs, whether those declared explicitly or arising from arrays, means that optimizers must be cautious, and must use careful dataflow techniques to achieve good results. Sophisticated compilers can understand what most pointers can possibly change, but some important usages remain difficult to analyze. For example, functions with pointer arguments derived from arrays are hard to compile into efficient code on vector machines, because it is seldom possible to determine that one argument pointer does not overlap data also referred to by another argument, or accessible externally. More fundamentally, the definition of C so specifically describes the semantics of arrays that changes or extensions treating arrays as more primitive objects, and permitting operations on them as wholes, become hard to fit into the existing language. Even extensions to permit the declaration and use of multidimensional arrays whose size is determined dynamically are not entirely straightforward [MacDonald 89] [Ritchie 90], although they would make it much easier to write numerical libraries in C. Thus, C covers the most important uses of strings and arrays arising in practice by a uniform and simple mechanism, but leaves problems for highly efficient implementations and for extensions.

C++ has addressed most of these array critique points (apart from dynamic arrays...).
Highly efficient implementation is now possible. This extension to array return is possible.
C++'s object model addresses aliasing, so correct C++ code can be as efficient as Fortran.
As long as decay to pointer is avoided, the program retains full information for array object-type.
References allow passing sized arrays to functions, so 'permitting operations on them as wholes'.

With references, passing array by value is not necessary;
it is inconsistent that you cannot pass array by value but references make this unimportant.
Allowing a callee to allocate and return array static storage is more important, as functions can then
wrap array creation rather than taking as an argument a mutable reference to a pre-declared array.

C-array and std::array are different tools for different tasks.

The general argument against your proposal is that they should not be viewed that way. 
That `std::array` ought to be viewed as fixed version of C-arrays

I was wrong to say 'different tools'; C-array is a building block, std::array an edifice.
Similarly, although std::array attempts to fix C-array, it has to do so by wrapping C-array.

we should endeavor to make `std::array` more palatable in places where it is problematic, 
rather than trying to make C-arrays more functional.

We should do both. This is C++; if we can, we do.

std::array aimed at a strong data-hiding abstraction.
More recent additions to C++, like structured binding, make data more manifest.
Eventually, static reflection blows open all hidden data, including C-array members.
C-array compatibility then grows in importance.

std::array 'palatability' improvement should be a new thread...
... but, since it is raised here, let's totally raise the edifice and try to patch it up.

Here's a way to fork std::array:

template <typename T, std::size_t... E> struct array;

template <typename T, std::size_t N> struct array<T,N>
                                     
{ T data[N]{}; }; // std array

template <typename T, std::size_t N> struct array<T[N]>
                                     
{ /* ? */ };  // improved array

Then std::array<int[4]> gives a new improved array.

This way, we could also add std::array_ref as a reference wrapper specific to C-array -
a std compatibility wrapper for existing C-array, including multi-dimensional.

int m44[4][4];
array_ref
{m44}; // copyable, copy-assignable from array, comparable, etc.

Strange how 'two world-view' conflict burns on; I hadn't mean to spark flame-wars of old
(weren't flame wars fought between languages, not one language burning its foundation). 

Matthew Woehlke

unread,
Feb 20, 2019, 2:25:06 PM2/20/19
to std-pr...@isocpp.org, Jake Arkinstall
On 19/02/2019 11.30, Jake Arkinstall wrote:
> On Tue, 19 Feb 2019, 15:52 will wray wrote:
>> Raw arrays deserve to be rehabilitated, with a little language level love.
>
> I'm not so sure on that. std::array gives the compiler the knowledge of the
> size so that the user doesn't have to pass it around manually

Eh?

void foo(int (&arr)[4]);
void foo(std::array<int, 4>& arr);

The compiler knows the size in both cases. I guess you are comparing to:

void foo(int arr[]);

...but that's not really apples-to-apples, being closer to:

void (int* arr);

--
Matthew

Matthew Woehlke

unread,
Feb 20, 2019, 2:33:41 PM2/20/19
to std-pr...@isocpp.org, Nicol Bolas
On 19/02/2019 22.55, Nicol Bolas wrote:
> From a more objective POV, my feeling is that `std::array` really only has
> two significant flaws relative to to C arrays: not being able to omit the
> size of an array while still specifying the type (which is a matter of
> CTAD), and the general verbosity of multi-dimensional arrays.

Well, I can help with the second... shortest ever proposal?

namespace std
{
template <typename T, size_t First, size_t... N>
struct array : array<array<T, N...>, First> {};
}

Example:

std::array<int, 5, 3, 4> x;
x[1][1][1] = 42;

Implementing operator() to do multi-level indexing is left as an
exercise for the reader.

Of course, the reason we don't have this yet is because folks want to
argue about packing order and whatnot. It turns out multi-dimensional
arrays aren't actually as simple as you'd think.

--
Matthew

Gašper Ažman

unread,
Feb 20, 2019, 2:35:18 PM2/20/19
to std-pr...@isocpp.org, Nicol Bolas
Except sometimes, when they are, and this is exactly what one would need.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/1e6e2f7e-cc29-7f39-f421-3674cd71ce14%40gmail.com.

Pedro Alves

unread,
Feb 21, 2019, 6:48:20 AM2/21/19
to std-pr...@isocpp.org, Nicol Bolas
On 02/20/2019 03:55 AM, Nicol Bolas wrote:
>
> On a personal level, the biggest problem I have with increasing the use of C-arrays is syntactic. Just look at one of your examples:
>
> char abc1D()[3] { return {'a','b','c'}; }
>
> If the `[3]` applies to the `char` as part of the return type, why is it on the other side of the function name? The return type should be either on the left or the right; it shouldn't be scattered between them. My first thought was that you were somehow creating an array of functions, not a function that returns an array.

Not arguing for this in any way, but I'd think that
syntax-wise, this would be much clearer:

auto abc1D()-> char[3] { return {'a','b','c'}; }

Curiously, seems like that actually compiled with GCC up until v7. See:

https://godbolt.org/z/aE5l8I

gcc 8 errors out with
error: 'abc1D' declared as function returning an array
and clang errors out with
error: function cannot return array type 'char [3]'

Pedro Alves

Pedro Alves

unread,
Feb 21, 2019, 7:04:35 AM2/21/19
to std-pr...@isocpp.org, Nicol Bolas
Also curiously, and for completeness, I should add that all of gcc,
clang and msvc already parse the proposed syntax as intended:

https://godbolt.org/z/q848pW

As can be seen from the error messages (here gcc):

<source>:1:15: error: 'abc1D' declared as function returning an array

I couldn't find a gcc version that actually accepts that syntax without
error, unlike the trailing return type version.

This seems to suggest that the syntax would be a natural fit
for the grammar, at least.

Pedro Alves
Reply all
Reply to author
Forward
0 new messages