Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
January 06, 2014 pure static | ||||
---|---|---|---|---|
| ||||
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 |
January 06, 2014 Re: pure static | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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.
|
January 06, 2014 Re: pure static | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | 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
|
January 06, 2014 Re: pure static | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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,
> bearophile
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.
|
January 07, 2014 Re: pure static | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | 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
|
January 07, 2014 Re: pure static | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Tuesday, 7 January 2014 at 00:54:10 UTC, bearophile wrote:
> 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
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?
|
January 07, 2014 Re: pure static | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | 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 |
January 07, 2014 Re: pure static | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Tuesday, 7 January 2014 at 00:54:10 UTC, bearophile wrote:
> 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
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;
}
|
Copyright © 1999-2021 by the D Language Foundation