www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Did the implicit conversion from special slice expression to static

reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
In the [Expression § Slice Conversion to Static 
Array](https://dlang.org/spec/expression.html#slice_to_static_array), at the
end of the section, it says:
 Certain other forms of slice expression can be implicitly 
 converted to a static array when the slice length can be known 
 at compile-time.
And you find this table (assuming `e` is an expression that contains no side effects and `a` and `b` are compile-time known integers): | Form | The length calculated at compile time | |-------------------|---------------------------------------| | `arr[]` | `arr.length` if known at compile-time | | `arr[a .. b]` | `b - a` | | `arr[e-a .. e]` | `a` | | `arr[e .. e+b]` | `b` | | `arr[e-a .. e+b]` | `a + b` | | `arr[e+a .. e+b]` | `b - a` if `a` ≤ `b` | | `arr[e-a .. e-b]` | `a - b` if `a` ≥ `b` | 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. 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 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.
Sep 22 2022
next sibling parent reply Nick Treleaven <nick geany.org> writes:
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 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.
 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.
Sep 22 2022
next sibling parent Nick Treleaven <nick geany.org> writes:
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:
 ```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
 ```
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.
Or rather *cannot be* statically known. I.e. `int[1] = da;` is allowed.
Sep 22 2022
prev sibling parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
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.
Sep 22 2022
parent Nick Treleaven <nick geany.org> writes:
On Thursday, 22 September 2022 at 14:31:46 UTC, Quirin Schroll 
wrote:
 On Thursday, 22 September 2022 at 12:48:18 UTC, Nick Treleaven 
 wrote:
 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.
Well I said a const runtime value should work (not just a compile-time constant as works now). const there would make it easy for the compiler to tell there are no side effects. I think you are right that a mutable variable simple lvalue should work as well. Some expressions do have side effects and to ensure every kind of non-side effect expression might require an optimization pass. I found this is in bugzilla where `m_data[offset .. offset + 14];` is not recognised: https://issues.dlang.org/show_bug.cgi?id=9165#c1
Sep 22 2022
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Thursday, 22 September 2022 at 10:50:28 UTC, Quirin Schroll 
wrote:
 Has it ever worked?
It looks like the docs were merged but the compiler pull was not merged: https://github.com/dlang/dmd/pull/4209#issuecomment-74065882 Before I found that I implemented `arr[e .. e+b]` for a simple variable `e`: https://github.com/ntrel/dmd/commits/slice-size I think at least that should be supported, probably the most common of all the non-constant index forms. But the original pull works for lots of other side-effect free expressions, besides the other forms.
Sep 23 2022
parent Nick Treleaven <nick geany.org> writes:
On Friday, 23 September 2022 at 13:35:31 UTC, Nick Treleaven 
wrote:
 It looks like the docs were merged but the compiler pull was 
 not merged:
 https://github.com/dlang/dmd/pull/4209#issuecomment-74065882
Commented out those docs & fixed other examples: https://github.com/dlang/dlang.org/pull/3416
Sep 24 2022