January 06, 2021
From the feedback thread:

On Wednesday, 6 January 2021 at 17:54:34 UTC, Dukc wrote:
> `std.array.staticArray` can already handle most of the problems described, and it does work in betterC - I just tested with LDC 1.20.1 targeting WebAssembly. while there are remaining cases (`auto fun(int[$] = [1,2,3])` isn't easy to represent now), I suspect they are a bit too trivial to justify a new feature.

Type inference for parameters with a default argument could be made to work.

auto fun(auto a = [1,2,3].staticArray) {return a;}

> On to refining the feature if it's accepted anyway. This should work:
> ```
> int[$] bar(int[2] arr)              // Error: not allowed in functions declarations
> {
>     return arr ~ [3, 4];
> }
> ```
> Why? because you can use `auto` as return type. `Type[$]` should IMO work anywhere `auto` does.

The inferred return type is int[], and causes an error if the return type is specified as int[4].

> You need to mention that this DIP will break code in this, admittedly rare, case:
> ```
> int[] x = something;
> int y = something[0 .. staticArrFunc(cast(int[$])[1,2,3])];
> ```

Excellent point, but it isn't just casts, anywhere you use a type (template instantiation) that is within an indexing expression will have this problem.

> I wonder if `$` should be allowed inside an expression, like this:
> ```
> int[$+2] a = [1,2,3]; //static array of [1,2,3,0,0]
> ```

Not worth it, easy to workaround.
January 06, 2021
On Wednesday, 6 January 2021 at 17:59:57 UTC, Jacob Carlborg wrote:
> There's `staticArray` to solve this issue [1].

It does a slightly different thing. staticArray works with types of literals and values, while the proposed way works with type of the declaration. Now you have to either infer the whole type (`auto`) or not infer anything at all. This proposal would let one to infer the length of a static array without inferring it's type. For example, `short[$] arr = [1,2,3]` isn't easily representable with `staticArray`, as `is(typeof([1,2,3].staticArray) == int[3])`.

Whether the issues are different enough to justify a new language feature is another question though.
January 06, 2021
On Wednesday, 6 January 2021 at 18:14:42 UTC, Luhrel wrote:
> It works only for the `int` type and above (and other types as structs).
>
> example with short:
> ---
> extern(C) void main()
> {
>     import std.array;
>     auto a = [0, 1].staticArray!short;  // error
> }

Can be fixed (probably with another name):

//import std.array;
import std.stdio;

void main(){
    auto a = [1,2,3].staticArray!float;
    pragma(msg, typeof(a)); // float[3]
    a.writeln();
}

template staticArray(T) {
    T[n] staticArray(ulong n) (auto ref T[n] a) {return a;}
}

January 06, 2021
On Wednesday, 6 January 2021 at 18:22:32 UTC, Nick Treleaven wrote:
> Type inference for parameters with a default argument could be made to work.
>
> auto fun(auto a = [1,2,3].staticArray) {return a;}

Okay that was a bad example. But see Luhrels answer to Jacob.

>> ```
>> int[$] bar(int[2] arr)              // Error: not allowed in functions declarations
>> {
>>     return arr ~ [3, 4];
>> }
>> ```
>
> causes an error if the return type is specified as int[4].

Why? `arr` is static so the compiler should be able to figure that no overflow will ever happen.

>> ```
>> int[] x = something;
>> int y = something[0 .. staticArrFunc(cast(int[$])[1,2,3])];
>> ```
>
> Excellent point, but it isn't just casts, anywhere you use a type (template instantiation) that is within an indexing expression will have this problem.

Yeah, this is just the simplest example that came to mind.


January 06, 2021
On Wednesday, 6 January 2021 at 18:29:05 UTC, Nick Treleaven wrote:
> Can be fixed (probably with another name):
>
> //import std.array;

Actually template overloading seems to work fine:

template staticArray(T) {
    T[n] staticArray(ulong n) (auto ref T[n] a) {return a;}
}

T[n] staticArray(T, ulong n) (auto ref T[n] a) {return a;}

void main(){
    auto a = [1,2,3].staticArray!float;
    pragma(msg, typeof(a)); // float[3]
    a.writeln();
    [1,2,3].staticArray.writeln();
}

January 06, 2021
On Wednesday, 6 January 2021 at 18:33:54 UTC, Dukc wrote:
>>> ```
>>> int[$] bar(int[2] arr)              // Error: not allowed in functions declarations
>>> {
>>>     return arr ~ [3, 4];
>>> }
>>> ```
>>
>> causes an error if the return type is specified as int[4].
>
> Why? `arr` is static so the compiler should be able to figure that no overflow will ever happen.

Because:
1. concatenation with a static array is not defined (use `arr[]`).
2. slices do not implicitly convert to a static array.

January 06, 2021
On Wednesday, 6 January 2021 at 18:41:31 UTC, Nick Treleaven wrote:
> On Wednesday, 6 January 2021 at 18:33:54 UTC, Dukc wrote:
>> Why? `arr` is static so the compiler should be able to figure that no overflow will ever happen.
>
> Because:
> 1. concatenation with a static array is not defined (use `arr[]`).

Oh okay.

> 2. slices do not implicitly convert to a static array.

They do if the length is known at compile time, but `~` does not for some reason propagate the length. This works though:

```
int[4] bar(int[2] arr)
{   return arr.conc([3, 4]);
}

T[i+j] conc(T, size_t i, size_t j)(T[i] a, T[j] b)
{	typeof(return) result;
	result[0 .. i] = a[];
	result[i .. $] = b[];
	return result;
}
```

January 06, 2021
On Wednesday, 6 January 2021 at 18:34:31 UTC, Nick Treleaven wrote:
> On Wednesday, 6 January 2021 at 18:29:05 UTC, Nick Treleaven wrote:
>> Can be fixed (probably with another name):
>>
>> //import std.array;
>
> Actually template overloading seems to work fine:
>
> template staticArray(T) {
>     T[n] staticArray(ulong n) (auto ref T[n] a) {return a;}
> }
>
> T[n] staticArray(T, ulong n) (auto ref T[n] a) {return a;}
>
> void main(){
>     auto a = [1,2,3].staticArray!float;
>     pragma(msg, typeof(a)); // float[3]
>     a.writeln();
>     [1,2,3].staticArray.writeln();
> }

What about something like below to handle any user-defined type.

import std.stdio: writeln;

template staticArray(T) {
    T[n] staticArray(ulong n) (auto ref T[n] a) {return a;}

    T[n] staticArray(U, ulong n) (auto ref U[n] a)
        if (!is(T == U))
    {
        T[n] output;
        for(size_t i = 0; i < n; i++) {
            output[i] = cast(T) a[i];
        }
        return output;
    }
}

T[n] staticArray(T, ulong n) (auto ref T[n] a) {return a;}

struct Foo {
    float x;
    T opCast(T)() {
        return cast(T) x;
    }
}

void main(){
    auto a = [1,2,3].staticArray!float;
    pragma(msg, typeof(a)); // float[3]
    a.writeln();
    [1,2,3].staticArray.writeln();

    auto b = [1,2,3].staticArray!Foo;
    b.writeln();
}

January 06, 2021
On Wednesday, 6 January 2021 at 18:34:31 UTC, Nick Treleaven wrote:
> On Wednesday, 6 January 2021 at 18:29:05 UTC, Nick Treleaven wrote:
>> Can be fixed (probably with another name):
>>
>> //import std.array;
>
> Actually template overloading seems to work fine:
>
> template staticArray(T) {
>     T[n] staticArray(ulong n) (auto ref T[n] a) {return a;}
> }
>
> T[n] staticArray(T, ulong n) (auto ref T[n] a) {return a;}
>
> void main(){
>     auto a = [1,2,3].staticArray!float;
>     pragma(msg, typeof(a)); // float[3]
>     a.writeln();
>     [1,2,3].staticArray.writeln();
> }

Still doesn't work with `short`.
January 06, 2021
On Wednesday, 6 January 2021 at 19:17:46 UTC, Luhrel wrote:
> [snip]
>
> Still doesn't work with `short`.

Pretty sure my version above does.