Did the implicit conversion from special slice expression to static array ever work?

Quirin Schroll qs.il.paperinik at gmail.com
Thu Sep 22 14:31:46 UTC 2022


On Thursday, 22 September 2022 at 12:48:18 UTC, Nick Treleaven 
wrote:
> On Thursday, 22 September 2022 at 10:50:28 UTC, Quirin Schroll 
> wrote:
>> Has it ever worked?
>>
>> Expanding on the code example
>> ```d
>> int[] da = [1, 2, 3];
>> int i = da[0]; // runtime variable
>>
>> int[2] sa2 = da[i .. i + 2];
>> assert(sa2 == [2, 3]);
>>
>> // my tests
>> int[1] sa1 = da[i .. i + 2]; // core.exception.RangeError
>> int[3] sa3 = da[i .. i + 2]; // core.exception.RangeError
>> ```
>> It seems like there is not attempt made to check the lengths 
>> at compile-time. The specification in a sense promised me a 
>> compile error here.
>
> The problem is that you can initialize a static array from (or 
> assign to) a slice, even when the slice length is not 
> statically known. I started a thread on that:
> https://forum.dlang.org/post/kqolsorsdmlshxhdqbpq@forum.dlang.org

I think this is the reason the assignment compiles anyways. This 
is however not the reason why there is no compile error pointing 
out a length mismatch. The spec says that both lengths are known 
at compile-time; thus, if equal, good, if not, it’s an error:
```d
int i = 1;
int[3] xs = [ 0, i, i+1, i+3 ]; // compile-error (length mismatch)
```
The literal is not a constant (it includes run-time values). 
However, the length is statically known and mismatches.

> I did then update the docs to document that:
> https://dlang.org/spec/arrays.html#assignment
>
> I think this is surprising because a slice does not implicitly 
> convert to a static array in general, e.g. when passing one to 
> a static array function parameter.
>
>> On the other hand, I tried with this code:
>> ```d
>> void f(T, size_t n)(T[n] array) { }
>>
>> void main()
>> {
>>     int[] xs = [1,2,3,4,5,6];
>>     size_t i = 2;
>>     f(xs[i .. i+3]); // compile error
>> }
>> ```
>> It did not work with any compiler supported by 
>> [run.dlang.io](https://run.dlang.io/) (LDC and any DMD since 
>> 2.064, including beta and nightly).
>
> If you make `i` const, it does work, but it has to be 
> initialized from a compile-time expression too. It should work 
> with a runtime initializer so long as `i` is const.

This misses the point entirely. The spec is about run-time 
expressions. It is very clear about that implicitly using the 
phrase “no side effects”. Reading a compile-time constant is a 
very special case of no side effects.

Effectively, the idea is that there’s a run-time value involved, 
but it serves only as the offset and does not change the length 
of the segment being sliced (because the values cancel). The 
whole thing would be trivial if syntax existed for it, e.g. 
`slice[i: 3]` for `slice[i..i+3]` where `i` would only be 
evaluated once. We could simply say: If the length is a 
compile-time constant, there it is.

>> If it does work in other contexts, either this feature should 
>> be removed (it does not work consistently) or be improved so 
>> that it lives up to its promise. If nothing like that is 
>> implemented, the section should be removed from the spec.
>
> Aside from breakage, assignment from a slice of unknown 
> compile-time length could be illegal - the user could easily 
> write `arr[] = slice` instead.
>
> That makes it clear that slice copying is happening, which has 
> a runtime check for matching lengths.
>
> For initialization, statically-known slice length could be 
> required. Failing that, at least requiring `slice[]` on an 
> lvalue initializer would make it clear it is initialization 
> from a slice.

+1 to that.


More information about the Digitalmars-d mailing list