digitalmars.D.learn - inferred size for static array initialization
- Erik Smith (8/8) May 02 2016 Is there a way to initialize a static array and have it's size
- Basile B (16/25) May 02 2016 Help yourself with a template:
- Basile B (10/36) May 02 2016 Using an enum is probably a bit better
- Marco Leise (11/21) May 02 2016 Sure,
- ag0aep6g (2/3) May 02 2016 `static enum`? What kind of black magic is this?
- Marco Leise (5/9) May 02 2016 I don't know, but it works, haha.
- Erik Smith (19/19) May 02 2016 I tried to combine the two solutions (Basile with the wrapper,
- Namespace (18/27) May 02 2016 I still like
- Steven Schveighoffer (8/35) May 02 2016 And this is the problem.
- Namespace (7/12) May 02 2016 This works:
- Namespace (3/10) May 02 2016 Of course this slice is only valid as long as you dont leave the
- Steven Schveighoffer (12/21) May 02 2016 No, because 'as' is pointing at stack space no longer allocated. It may
- Namespace (5/31) May 02 2016 The assembler looks different than that but I may be wrong and I
- Steven Schveighoffer (10/42) May 02 2016 The assembler might be safe in some instances, but that doesn't reflect
- Namespace (3/9) May 02 2016 Not quite. Look for yourself:
- Steven Schveighoffer (14/24) May 02 2016 Except for offsets, it looks identical. May be the compiler puts things
- Namespace (3/32) May 02 2016 I used it very often, but always assigned the result to an
- Steven Schveighoffer (6/8) May 02 2016 Using auto is fine, but the slice should not happen if you are assigning...
- Basile B. (6/11) May 03 2016 Wooah, this trick is awesome. But actually it does the same thing
- =?UTF-8?B?Tm9yZGzDtnc=?= (4/5) Oct 18 2016 Will that have zero run-time overhead compared to:
- Steven Schveighoffer (6/10) Oct 18 2016 Neither will have zero runtime overhead, but use the disassembler to see...
- Namespace (6/11) Oct 18 2016 I'm not quite sure if pragma(inline, true) would result in zero
Is there a way to initialize a static array and have it's size inferred (and that works for arrays of structs using braced literals)? This would make it easier to maintain longer static array definitions. The code below doesn't work when removing the array size even though the array is declared as static immutable. import std.traits; static immutable int[] a = [1,2,3]; static assert(isStaticArray!(typeof(a))); // fails
May 02 2016
On Monday, 2 May 2016 at 13:00:27 UTC, Erik Smith wrote:Is there a way to initialize a static array and have it's size inferred (and that works for arrays of structs using braced literals)? This would make it easier to maintain longer static array definitions. The code below doesn't work when removing the array size even though the array is declared as static immutable. import std.traits; static immutable int[] a = [1,2,3]; static assert(isStaticArray!(typeof(a))); // failsHelp yourself with a template: ---- import std.traits; auto toStaticArray(alias array)() if (isArray!(typeof(array))) { enum size = array.length; alias T = typeof(array.init[0])[size]; T result = array[0..size]; return result; } enum a = toStaticArray!([1,2,3]); static assert(isStaticArray!(typeof(a))); // success ---- Does it fit ?
May 02 2016
On Monday, 2 May 2016 at 13:22:01 UTC, Basile B wrote:On Monday, 2 May 2016 at 13:00:27 UTC, Erik Smith wrote:Using an enum is probably a bit better ---- auto toStaticArray(alias array)() if (isDynamicArray!(typeof(array)) && array.length) { alias T = typeof(array[0])[array.length]; enum T result = array[0..array.length]; return result; }Is there a way to initialize a static array and have it's size inferred (and that works for arrays of structs using braced literals)? This would make it easier to maintain longer static array definitions. The code below doesn't work when removing the array size even though the array is declared as static immutable. import std.traits; static immutable int[] a = [1,2,3]; static assert(isStaticArray!(typeof(a))); // failsHelp yourself with a template: ---- import std.traits; auto toStaticArray(alias array)() if (isArray!(typeof(array))) { enum size = array.length; alias T = typeof(array.init[0])[size]; T result = array[0..size]; return result; } enum a = toStaticArray!([1,2,3]); static assert(isStaticArray!(typeof(a))); // success ---- Does it fit ?
May 02 2016
Am Mon, 02 May 2016 13:00:27 +0000 schrieb Erik Smith <erik cruiserhouse.com>:Is there a way to initialize a static array and have it's size inferred (and that works for arrays of structs using braced literals)? This would make it easier to maintain longer static array definitions. The code below doesn't work when removing the array size even though the array is declared as static immutable. import std.traits; static immutable int[] a = [1,2,3]; static assert(isStaticArray!(typeof(a))); // failsSure, struct S { int a, b; } immutable tab = { static enum S[] s = [ {1,2}, {3,4}, ]; return cast(typeof(s[0])[s.length])s; }(); static assert(isStaticArray!(typeof(tab))); // succeeds -- Marco
May 02 2016
On 02.05.2016 15:53, Marco Leise wrote:immutable tab = { static enum S[] s = [`static enum`? What kind of black magic is this?
May 02 2016
Am Mon, 2 May 2016 18:52:11 +0200 schrieb ag0aep6g <anonymous example.com>:On 02.05.2016 15:53, Marco Leise wrote:I don't know, but it works, haha. -- Marcoimmutable tab = { static enum S[] s = [`static enum`? What kind of black magic is this?
May 02 2016
I tried to combine the two solutions (Basile with the wrapper, Marco with the struct initializer support) but it didn't work. The struct initializer is not a array literal (seems obvious now). I might go with the 2nd but it's pretty heavy just to get the size. Thanks. struct S { int a, b; } auto toStaticArray(alias array)() { struct S { int a, b; } immutable tab = { static enum S[] s = array; return cast(typeof(s[0])[s.length])s; }(); return tab; } enum a = toStaticArray!([{1,2},{3,4}]); // error
May 02 2016
On Monday, 2 May 2016 at 13:00:27 UTC, Erik Smith wrote:Is there a way to initialize a static array and have it's size inferred (and that works for arrays of structs using braced literals)? This would make it easier to maintain longer static array definitions. The code below doesn't work when removing the array size even though the array is declared as static immutable. import std.traits; static immutable int[] a = [1,2,3]; static assert(isStaticArray!(typeof(a))); // failsI still like ---- auto s(T, size_t n)(T[n] arr) { return arr; } auto arr = [1, 2, 3].s; ---- But of course this won't work: ---- int[] a = [1,2,3].s; static assert(isStaticArray!(typeof(a))); // fails ---- Since 'a' is just a slice. But this will work: ---- immutable auto a = [1,2,3].s; ----
May 02 2016
On 5/2/16 1:43 PM, Namespace wrote:On Monday, 2 May 2016 at 13:00:27 UTC, Erik Smith wrote:Interesting. But there is a major problem here...Is there a way to initialize a static array and have it's size inferred (and that works for arrays of structs using braced literals)? This would make it easier to maintain longer static array definitions. The code below doesn't work when removing the array size even though the array is declared as static immutable. import std.traits; static immutable int[] a = [1,2,3]; static assert(isStaticArray!(typeof(a))); // failsI still like ---- auto s(T, size_t n)(T[n] arr) { return arr; }auto arr = [1, 2, 3].s; ---- But of course this won't work: ---- int[] a = [1,2,3].s; static assert(isStaticArray!(typeof(a))); // fails ----And this is the problem.Since 'a' is just a slice.A slice of a no-longer-existing temporary! Admittedly, this is not an issue with your code, but a deeper issue of allowing slicing of rvalues.But this will work: ---- immutable auto a = [1,2,3].s; ----You can drop auto. It's just a placeholder for the storage class in the case where a storage class isn't specified. -Steve
May 02 2016
A slice of a no-longer-existing temporary! Admittedly, this is not an issue with your code, but a deeper issue of allowing slicing of rvalues.This works: ---- int[] as = [1, 2, 3].s; writeln(as[2]); ---- Bug or feature? Or did I may misunderstood you?You can drop auto. It's just a placeholder for the storage class in the case where a storage class isn't specified.Right, I forgot, it's a bit since I wrote something in D.
May 02 2016
On Monday, 2 May 2016 at 18:57:49 UTC, Namespace wrote:Of course this slice is only valid as long as you dont leave the scope. That's maybe what you tried to say, right?A slice of a no-longer-existing temporary! Admittedly, this is not an issue with your code, but a deeper issue of allowing slicing of rvalues.This works: ---- int[] as = [1, 2, 3].s; writeln(as[2]);
May 02 2016
On 5/2/16 3:02 PM, Namespace wrote:On Monday, 2 May 2016 at 18:57:49 UTC, Namespace wrote:No, because 'as' is pointing at stack space no longer allocated. It may work, and it may not, but having it work is not proof that it's sound. To make things clear, this is what your code effectively does: int[] as = void; { auto _tmp = [1, 2, 3].s; as = _tmp; } Which is not the same thing as having the static array a defined stack variable in the same scope. -SteveOf course this slice is only valid as long as you dont leave the scope. That's maybe what you tried to say, right?A slice of a no-longer-existing temporary! Admittedly, this is not an issue with your code, but a deeper issue of allowing slicing of rvalues.This works: ---- int[] as = [1, 2, 3].s; writeln(as[2]);
May 02 2016
On Monday, 2 May 2016 at 19:08:52 UTC, Steven Schveighoffer wrote:On 5/2/16 3:02 PM, Namespace wrote:The assembler looks different than that but I may be wrong and I only looked at gdc. But anyway, that means with 'pragma(inline, true)' I'm save. Is that right?On Monday, 2 May 2016 at 18:57:49 UTC, Namespace wrote:No, because 'as' is pointing at stack space no longer allocated. It may work, and it may not, but having it work is not proof that it's sound. To make things clear, this is what your code effectively does: int[] as = void; { auto _tmp = [1, 2, 3].s; as = _tmp; } Which is not the same thing as having the static array a defined stack variable in the same scope. -SteveOf course this slice is only valid as long as you dont leave the scope. That's maybe what you tried to say, right?A slice of a no-longer-existing temporary! Admittedly, this is not an issue with your code, but a deeper issue of allowing slicing of rvalues.This works: ---- int[] as = [1, 2, 3].s; writeln(as[2]);
May 02 2016
On 5/2/16 3:12 PM, Namespace wrote:On Monday, 2 May 2016 at 19:08:52 UTC, Steven Schveighoffer wrote:The assembler might be safe in some instances, but that doesn't reflect the original internal representation in the compiler. Some other configuration of calls may allow the compiler to reuse that memory, and then you run into problems. I'm wondering if you used my rewrite if it would actually output the same thing? But in any case, I don't know the answer to the pragma(inline) thing. I would guess it is subject to the same issues, but I'm not 100% sure. -SteveOn 5/2/16 3:02 PM, Namespace wrote:The assembler looks different than that but I may be wrong and I only looked at gdc. But anyway, that means with 'pragma(inline, true)' I'm save. Is that right?On Monday, 2 May 2016 at 18:57:49 UTC, Namespace wrote:No, because 'as' is pointing at stack space no longer allocated. It may work, and it may not, but having it work is not proof that it's sound. To make things clear, this is what your code effectively does: int[] as = void; { auto _tmp = [1, 2, 3].s; as = _tmp; } Which is not the same thing as having the static array a defined stack variable in the same scope.Of course this slice is only valid as long as you dont leave the scope. That's maybe what you tried to say, right?A slice of a no-longer-existing temporary! Admittedly, this is not an issue with your code, but a deeper issue of allowing slicing of rvalues.This works: ---- int[] as = [1, 2, 3].s; writeln(as[2]);
May 02 2016
The assembler might be safe in some instances, but that doesn't reflect the original internal representation in the compiler. Some other configuration of calls may allow the compiler to reuse that memory, and then you run into problems. I'm wondering if you used my rewrite if it would actually output the same thing?Not quite. Look for yourself: https://godbolt.org/g/kO8hdW https://godbolt.org/g/KCfYPy
May 02 2016
On 5/2/16 3:38 PM, Namespace wrote:Except for offsets, it looks identical. May be the compiler puts things in different spots for different ways of writing. But the thing that's not disclosed here is: what happens when the compiler feels the need to reuse that stack space? Your example doesn't have anything that may compete for the space, it just returns after this is over. For example, define a static array of exactly the same size to use after the call: int[3] x; Now, see if x is pigeonholed into that same place your temporary return existed (and therefore 'as' points at it). I'm still fully on the side of this being unsafe. -SteveThe assembler might be safe in some instances, but that doesn't reflect the original internal representation in the compiler. Some other configuration of calls may allow the compiler to reuse that memory, and then you run into problems. I'm wondering if you used my rewrite if it would actually output the same thing?Not quite. Look for yourself: https://godbolt.org/g/kO8hdW https://godbolt.org/g/KCfYPy
May 02 2016
On Monday, 2 May 2016 at 20:05:15 UTC, Steven Schveighoffer wrote:On 5/2/16 3:38 PM, Namespace wrote:I used it very often, but always assigned the result to an auto-type variable, never to a slice.Except for offsets, it looks identical. May be the compiler puts things in different spots for different ways of writing. But the thing that's not disclosed here is: what happens when the compiler feels the need to reuse that stack space? Your example doesn't have anything that may compete for the space, it just returns after this is over. For example, define a static array of exactly the same size to use after the call: int[3] x; Now, see if x is pigeonholed into that same place your temporary return existed (and therefore 'as' points at it). I'm still fully on the side of this being unsafe. -SteveThe assembler might be safe in some instances, but that doesn't reflect the original internal representation in the compiler. Some other configuration of calls may allow the compiler to reuse that memory, and then you run into problems. I'm wondering if you used my rewrite if it would actually output the same thing?Not quite. Look for yourself: https://godbolt.org/g/kO8hdW https://godbolt.org/g/KCfYPy
May 02 2016
On 5/2/16 4:14 PM, Namespace wrote:I used it very often, but always assigned the result to an auto-type variable, never to a slice.Using auto is fine, but the slice should not happen if you are assigning slice to a local var. There is a bug report on this: https://issues.dlang.org/show_bug.cgi?id=12625, though it's not as focused as I think it should be. -Steve
May 02 2016
On Monday, 2 May 2016 at 17:43:56 UTC, Namespace wrote:I still like ---- auto s(T, size_t n)(T[n] arr) { return arr; }Wooah, this trick is awesome. But actually it does the same thing that what I've proposed before. Exactly the same code is generated. So I'd say that it's rather a matter of readability. https://godbolt.org/g/wGTs52 https://godbolt.org/g/cXECyO
May 03 2016
On Monday, 2 May 2016 at 17:43:56 UTC, Namespace wrote:immutable auto a = [1,2,3].s;Will that have zero run-time overhead compared to: immutable int[3] a = [1,2,3]; ?
Oct 18 2016
On 10/18/16 6:35 AM, Nordlöw wrote:On Monday, 2 May 2016 at 17:43:56 UTC, Namespace wrote:Neither will have zero runtime overhead, but use the disassembler to see if there is a difference. My understanding is that while the compiler used to allocate whenever it saw an array literal (including your above usage), that is no longer the case. -Steveimmutable auto a = [1,2,3].s;Will that have zero run-time overhead compared to: immutable int[3] a = [1,2,3];
Oct 18 2016
On Tuesday, 18 October 2016 at 10:35:44 UTC, Nordlöw wrote:On Monday, 2 May 2016 at 17:43:56 UTC, Namespace wrote:I'm not quite sure if pragma(inline, true) would result in zero runtime overhead, but without you have 3 lines of assembler more (with gdc). https://godbolt.org/g/JUjP1d https://godbolt.org/g/qaqylpimmutable auto a = [1,2,3].s;Will that have zero run-time overhead compared to: immutable int[3] a = [1,2,3]; ?
Oct 18 2016