purity and memory allocations/pointers

anonymous anonymous at example.com
Sat Aug 3 09:54:19 PDT 2013


On Saturday, 3 August 2013 at 15:59:22 UTC, monarch_dodra wrote:
> I'm a bit confused about where we draw the line with purity, 
> and memory.
>
> For example, take this "simple" function:
>
> //----
> char[] getMutableHello() pure
> {
>     return "hello".dup;
> }
> //----
>
> This seems like it will *always* create the same result, yet at 
> the same time, it calls the GC. "dup" could fail, amongst 
> others, meaning there is failed purity.
>
> Is this OK?

When `dup` fails, some Exception/Error is thrown and the function 
won't return. So, purity is not affected, I think. There's also 
`nothrow` when you want to rule out exceptions.

>
> :::::::::::::::::::::::::::::::::::::::::
>
> Where does purity mean when you are talking about 
> slices/pointers? Simply that they *point*/*reference* the same 
> payload? I mean:
>
> void main()
> {
>     auto a = getMutableHello();
>     auto b = getMutableHello();
>     assert(a == b); //OK
>     assert(a is b); //Derp :/
> }
>
> Did getMutableHello just violate its purity promise?

I'd say `pure` doesn't promise equality of memory addresses. I 
imagine it would be rather annoying if you couldn't `new` in pure 
functions.

>
> :::::::::::::::::::::::::::::::::::::::::
>
> Another thing that bothers me, again, when interfacing with the 
> GC, is "capacity". It is currently marked as pure, but I 
> believe this is wrong: The GC can in-place extend the "useable" 
> memory of a dynamic array. This means all referencing slices 
> will be affected, yet un-modified. This means that calling 
> "s.capacity" depends on the global state of the GC:
>
> //----
>     auto s1 = new ubyte[](12_000);
>     auto bck = s1;
>     size_t cap = s1.capacity;
>     s1.reserve(13_000);
>     assert(s1 is bck); //Apparently, s1 is not changed.
>     assert(cap == s1.capacity); //This fails, yet capacity is 
> pure?
> //----
>
> Again, is this OK?

When you understand `capacity` as being referenced by the arrays, 
it's ok. Because then, of course `s1 is bck` even though its 
capacity changed. And `cap == s1.capacity` fails, because `cap` 
is a copy of an earlier state.

>
> :::::::::::::::::::::::::::::::::::::::::
>
> One last question: Pointers.
>
> int get(int* p) pure
> {
>     return *p;
> }
>
> void main()
> {
>     int i = 0;
>     auto p = &i;
>     get(p);
> }
>
> Here, get, to me, is obviously not pure, since it depends on 
> the state of the global "i". *Where* did "get" go wrong? Did I 
> simply "abusively" mark get as pure? Is the "pure" keyword's 
> guarantee simply "weak"?

By passing a pointer to `i`, you explicitly add it to the list of 
stuff, `get` may access (and alter).

Indeed, `pure` by itself only guarantees "weak purity". That 
means, the function may alter its arguments (and everything 
reachable from them). To get "strong purity", mark all arguments 
as const.

>
> :::::::::::::::::::::::::::::::::::::::::
>
> To sum up the question, regardless of how the *keyword* pure 
> currently works, my question is "*How* should it behave"? We're 
> currently marking things in Phobos as pure, and I'm worried the 
> only reason we are doing it is that the keyword is lenient, and 
> said functions *aren't* actually pure...

I think all cases you showed work as expected. For `pure` to 
really shine (strong purity), you need to add some `const` into 
the mix.

See also: http://dlang.org/function.html#pure-functions


More information about the Digitalmars-d mailing list