digitalmars.D - pure static
- bearophile (44/44) Jan 06 2014 Currently this compiles because arr gets copied (or moved)
- Timon Gehr (3/6) Jan 06 2014 It doesn't. The reinitialization may be observable through references
- bearophile (6/8) Jan 06 2014 Right, so that pure function can return only const data:
- Meta (4/49) Jan 06 2014 Why not just return arr.dup instead? You're returning a slice of
- bearophile (7/10) Jan 06 2014 In certain critical code paths heap allocations are evil (perhaps
- Meta (3/13) Jan 06 2014 But is it ever legal to return a local stack-allocated static
- bearophile (8/11) Jan 06 2014 It's legal because in D fixed-size arrays are values. So D copies
- TheFlyingFiddle (13/23) Jan 07 2014 Wouldn't it be better to simply allocate on the stack directly in
Currently this compiles because arr gets copied (or moved) (another less visible write of arr happens at the point of its initialization, it gets written by its init): int[5] foo() pure { int[5] arr; return arr; } void main() {} Currently even this function compiles, despite it's not actually pure, because arr contains garbage (and it's garbage that leaks information from other function stack frames, so it's a security hazard), so in theory a good compiler should disallow this: int[5] foo() pure { int[5] arr = void; return arr; } void main() {} On the other hand I think a strongly pure function like this could be accepted, avoiding the final copy of the result (the result contains a pointer to static data. Here the static data is an array, but returning a pointer to a static struct is equally valid): int[] foo() pure { pure static int[5] arr; return arr; } void main() {} "pure static" data means that 'arr' get cleaned (overwritten by its init) at the entry of the function foo (just like for not-static variables), to keep the function referentially transparent. So this is forbidden: pure static int[5] arr = void; A smart compiler can even see arr is fully assigned inside the function and optimize away the first clear of the array: int[] foo() pure { pure static int[5] arr; // optimized as =void foreach (immutable int i, ref r; arr) r = i; return arr; } void main() {} Bye, bearophile
Jan 06 2014
On 01/06/2014 09:35 PM, bearophile wrote:"pure static" data means that 'arr' get cleaned (overwritten by its init) at the entry of the function foo (just like for not-static variables), to keep the function referentially transparent.It doesn't. The reinitialization may be observable through references obtained from earlier calls.
Jan 06 2014
Timon Gehr:It doesn't. The reinitialization may be observable through references obtained from earlier calls.Right, so that pure function can return only const data: const(int[]) foo() pure { Is this idea still sufficiently useful? Perhaps not. Bye, bearophile
Jan 06 2014
On Monday, 6 January 2014 at 20:35:39 UTC, bearophile wrote:Currently this compiles because arr gets copied (or moved) (another less visible write of arr happens at the point of its initialization, it gets written by its init): int[5] foo() pure { int[5] arr; return arr; } void main() {} Currently even this function compiles, despite it's not actually pure, because arr contains garbage (and it's garbage that leaks information from other function stack frames, so it's a security hazard), so in theory a good compiler should disallow this: int[5] foo() pure { int[5] arr = void; return arr; } void main() {} On the other hand I think a strongly pure function like this could be accepted, avoiding the final copy of the result (the result contains a pointer to static data. Here the static data is an array, but returning a pointer to a static struct is equally valid): int[] foo() pure { pure static int[5] arr; return arr; } void main() {} "pure static" data means that 'arr' get cleaned (overwritten by its init) at the entry of the function foo (just like for not-static variables), to keep the function referentially transparent. So this is forbidden: pure static int[5] arr = void; A smart compiler can even see arr is fully assigned inside the function and optimize away the first clear of the array: int[] foo() pure { pure static int[5] arr; // optimized as =void foreach (immutable int i, ref r; arr) r = i; return arr; } void main() {} Bye, bearophileWhy not just return arr.dup instead? You're returning a slice of a stack-allocated array, so of course you shouldn't write code like this.
Jan 06 2014
Meta:Why not just return arr.dup instead? You're returning a slice of a stack-allocated array, so of course you shouldn't write code like this.In certain critical code paths heap allocations are evil (perhaps even if your generational GC has a stack-like nursery, that currently the D GC doesn't have) :-) And you also want to minimize copies and initializations. Bye, bearophile
Jan 06 2014
On Tuesday, 7 January 2014 at 00:54:10 UTC, bearophile wrote:Meta:But is it ever legal to return a local stack-allocated static array from a function in D? Won't that entail a copy either way?Why not just return arr.dup instead? You're returning a slice of a stack-allocated array, so of course you shouldn't write code like this.In certain critical code paths heap allocations are evil (perhaps even if your generational GC has a stack-like nursery, that currently the D GC doesn't have) :-) And you also want to minimize copies and initializations. Bye, bearophile
Jan 06 2014
Meta:But is it ever legal to return a local stack-allocated static array from a function in D?It's legal because in D fixed-size arrays are values. So D copies them (but in in some cases theory it can allocate them in the stack frame of the caller and avoid the copy).Won't that entail a copy either way?In the code I've shown I have used "pure static", so the array is allocated statically, not on the stack. Bye, bearophile
Jan 06 2014
On Tuesday, 7 January 2014 at 00:54:10 UTC, bearophile wrote:Meta:Wouldn't it be better to simply allocate on the stack directly in the calling function? Or if that is not a possibility use a region allocator or even a ScopeStack allocator? It's basically just a pointer bump so it should be fast. So it would translate to something like this: int[] foo(Allocator)(ref Allocator allocator) { auto arr = allocator.allocate!(int[])(5); foreach(i, ref elem; arr) elem = i; return arr; }Why not just return arr.dup instead? You're returning a slice of a stack-allocated array, so of course you shouldn't write code like this.In certain critical code paths heap allocations are evil (perhaps even if your generational GC has a stack-like nursery, that currently the D GC doesn't have) :-) And you also want to minimize copies and initializations. Bye, bearophile
Jan 07 2014