<p>C does not have first class arrays that can be assigned (copied) or returned from functions directly. In such a low level language where arrays are essentially pointers to the first value. This way, if, for example, a programmer assigns an array lvalue to another, the compiler does not know if the array data is being assigned or the pointer. There is no problem with actually assigning array data as we can assign structures with arrays in them.</p>
<p>What would be some possible semantics for a C-like language to support first class arrays?</p>

<c><arrays><first-class-objects>
How could C implement first class arrays?
<h2>Fat pointers</h2>
<p>One could define an array pointer as:</p>
<pre><code>struct Array {
    int length,
    int itemLength,
    void* contents
}
</code></pre>
<p>This matches how arrays are stored in rust. Unfortunatly C has no templates on generics so we are forced to use void pointers rather than specify the type of the pointer. If this was encoded in the compiler it something could be implemented for every type.</p>
<p>You could use it like this:</p>
<pre><code>void f(struct Array a) {
    for (int *i=a.contents; i&lt;a.contents + a.length * a.itemSize; i=i + a.itemSize / sizeof(int)) {
        printf(&quot;%d\n&quot;, *(long int*)i);
    } 
}

int main() {
    long int a[5] = {1,6,2,8,6};
    struct Array b = {5, sizeof(long), a};

    f(b);
}
</code></pre>
<p>If this was to be officially added to the language, there probably need both syntactic sugar for instantiating the struct more conveniently and in a less error prone way, and also iterating and access the items conveniently.</p>
<p>All of this is technically feasible though. The main barrier though is just that the C is intentionally kept very simple so strongly resists attempts to add new features like this.</p>

CC BY-SA 4.0
2023-05-17T19:06:02.687Z
2023-05-17T19:06:02.687Z
mousetail 'he-him'
CC BY-SA 4.0
2023-05-17T21:38:30.177Z
Memory ownership is a huge issue with this though, suppose I create an array structure in this style within a function and then return it, should the underlying memory be copied to the caller's stack, should the array be declared straight in heap, or a secret third option?
kouta-kun
CC BY-SA 4.0
2023-05-18T17:58:03.810Z
@kouta-kun you can't copy a dynamic amount of memory to the stack so it needs to stay in the heap. It needs to eventually be freed, probably by the caller. Making sure it gets freed exactly once will be the programmers job.
mousetail 'he-him'
CC BY-SA 4.0
2023-05-18T19:03:18.667Z
`alloca()` allows for dynamic stock allocation, doesn't it? Though I get what you mean now
kouta-kun
CC BY-SA 4.0
2023-05-18T19:08:47.947Z
True, but if you allocate the pointer with `alloca` you won't be able to return it since it lives on the stack frame. (I totally forgot `alloca` exists, you can actually allocate dynamic memory on the stack)
mousetail 'he-him'
<h1>Dependent types</h1>
<p>We may add a special case of template to C, say, a built-in version of <code>std::array</code>. Then, we can say for sure that whenever an instance of an array is passed around, the associated length value goes along with it. Then it remains to deal with decaying and backward compatibility.</p>

CC BY-SA 4.0
2023-05-17T00:42:02.780Z
2023-05-17T00:42:02.780Z
ice1000
<p>I've abused the preprocessor to implement first-class fat pointers, like @mousetail suggested, but a bit different:</p>
<pre><code>#define ARRAY_TYPE(T) struct { size_t len; T* a; }
</code></pre>
<p>Now you define an array type like this:</p>
<pre><code>typedef ARRAY_TYPE(int) int_arr_t;
</code></pre>
<p><code>int_arr_t</code> is now a fat pointer type for <code>int</code>.</p>
<p>This has the advantage of not storing extra data for the type size.</p>
<p>You can then define macros to give you bound-checked indexing and pointer arithmetic:</p>
<pre><code>#define idx(p, i)                                       \
    ((((size_t) (i)) &lt; (p).len) ?                       \
         (p).a[(size_t) (i)] :                          \
         (panic_impl( __FILE__, __LINE__, __func__,     \
                     &quot;index (%zu) is greater than the &quot; \
                     &quot;length of the array (%zu)&quot;,       \
                     (size_t) (i), (p).len),            \
          (p).a[0]))

#define ptr(p, i)                                       \
    ((((size_t) (i)) &lt; (p).len) ?                       \
         (p).a + ((size_t) (i)) :                       \
         (panic_impl(__FILE__, __LINE__, __func__,      \
                     &quot;index (%zu) is greater than the &quot; \
                     &quot;length of the array (%zu)&quot;,       \
                     (size_t) (i), (p).len),            \
          (p).a))
</code></pre>
<p>Note that since these macros just use field names, the macros work with any array type created with <code>ARRAY_TYPE</code>, and the pointer arithmetic is &quot;safe&quot; in that it uses the correct pointer type.</p>
<p>(This is an edited version of my <a href="https://git.yzena.com/Yzena/Yc/src/commit/80af8c2bd6a87fb549a35eab52fa0840d057309d/include/yc/array.h" rel="nofollow noreferrer">own code</a>. I hereby put the code above into the public domain because I want C to be as safe as possible. Please use freely!)</p>
<p><strong>Edit</strong>: You can easily make analogous bounds-check macros for the situation where the fat pointer struct is a pointer itself; I just added <code>p</code> on the end of the original macro name in that case.</p>

CC BY-SA 4.0
2023-05-17T20:05:46.600Z
2023-05-18T03:45:43.027Z
2023-05-18T03:45:43.027Z
Gavin D. Howard
# How could C implement first class arrays?
Posted by: username_0 on 2023-05-17
C does not have first class arrays that can be assigned (copied) or returned from functions directly. In such a low level language where arrays are essentially pointers to the first value. This way, if, for example, a programmer assigns an array lvalue to another, the compiler does not know if the array data is being assigned or the pointer. There is no problem with actually assigning array data as we can assign structures with arrays in them.

What would be some possible semantics for a C-like language to support first class arrays?
**Tags:** c arrays first-class-objects
---
## 3 answers
### Answer by username_4 on 2023-05-17. Score: 8 | Accepted answer
I've abused the preprocessor to implement first-class fat pointers, like @mousetail suggested, but a bit different:
#define ARRAY_TYPE(T) struct { size_t len; T* a; }

Now you define an array type like this:
typedef ARRAY_TYPE(int) int_arr_t;

int_arr_t is now a fat pointer type for int.
This has the advantage of not storing extra data for the type size.
You can then define macros to give you bound-checked indexing and pointer arithmetic:
#define idx(p, i)                                       \
    ((((size_t) (i)) < (p).len) ?                       \
         (p).a[(size_t) (i)] :                          \
         (panic_impl( __FILE__, __LINE__, __func__,     \
                     "index (%zu) is greater than the " \
                     "length of the array (%zu)",       \
                     (size_t) (i), (p).len),            \
          (p).a[0]))

#define ptr(p, i)                                       \
    ((((size_t) (i)) < (p).len) ?                       \
         (p).a + ((size_t) (i)) :                       \
         (panic_impl(__FILE__, __LINE__, __func__,      \
                     "index (%zu) is greater than the " \
                     "length of the array (%zu)",       \
                     (size_t) (i), (p).len),            \
          (p).a))

Note that since these macros just use field names, the macros work with any array type created with ARRAY_TYPE, and the pointer arithmetic is "safe" in that it uses the correct pointer type.
(This is an edited version of my own code. I hereby put the code above into the public domain because I want C to be as safe as possible. Please use freely!)
Edit: You can easily make analogous bounds-check macros for the situation where the fat pointer struct is a pointer itself; I just added p on the end of the original macro name in that case.
---
### Answer by username_1 on 2023-05-17. Score: 7
Fat pointers
One could define an array pointer as:
struct Array {
    int length,
    int itemLength,
    void* contents
}

This matches how arrays are stored in rust. Unfortunatly C has no templates on generics so we are forced to use void pointers rather than specify the type of the pointer. If this was encoded in the compiler it something could be implemented for every type.
You could use it like this:
void f(struct Array a) {
    for (int *i=a.contents; i
If this was to be officially added to the language, there probably need both syntactic sugar for instantiating the struct more conveniently and in a less error prone way, and also iterating and access the items conveniently.
All of this is technically feasible though. The main barrier though is just that the C is intentionally kept very simple so strongly resists attempts to add new features like this.
> **Comments:**
> **username_2** (2023-05-17): Memory ownership is a huge issue with this though, suppose I create an array structure in this style within a function and then return it, should the underlying memory be copied to the caller's stack, should the array be declared straight in heap, or a secret third option?  
> **username_1** (2023-05-18): @kouta-kun you can't copy a dynamic amount of memory to the stack so it needs to stay in the heap. It needs to eventually be freed, probably by the caller. Making sure it gets freed exactly once will be the programmers job.  
> **username_2** (2023-05-18): `alloca()` allows for dynamic stock allocation, doesn't it? Though I get what you mean now  
> **username_1** (2023-05-18): True, but if you allocate the pointer with `alloca` you won't be able to return it since it lives on the stack frame. (I totally forgot `alloca` exists, you can actually allocate dynamic memory on the stack)  
---
### Answer by username_3 on 2023-05-17. Score: 2
# Dependent types

We may add a special case of template to C, say, a built-in version of `std::array`. Then, we can say for sure that whenever an instance of an array is passed around, the associated length value goes along with it. Then it remains to deal with decaying and backward compatibility.
---
