digitalmars.D - GC.malloc is pure - wat
- anonymous (9/9) Apr 24 2015 GC.malloc is marked pure. But it isn't, is it?
- Adam D. Ruppe (6/6) Apr 24 2015 string toLower(string s);
- Steven Schveighoffer (19/28) Apr 24 2015 All functional make this concession -- allocating is pure as long as you...
- Steven Schveighoffer (3/6) Apr 24 2015 All functional *languages* make this concession...
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (7/10) Apr 24 2015 It does, but only in the same expression, i.e.
- anonymous (26/27) Apr 24 2015 Could you give a complete example of when this is done?
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (5/32) Apr 24 2015 Hmm... strange. I was convinced it worked that way. I used
- anonymous (6/9) Apr 24 2015 Ah, this is the piece I was missing. I was aware of weak/strong
- Steven Schveighoffer (6/14) Apr 24 2015 IMO, yes. But not everyone agrees with that.
- deadalnix (7/17) Apr 24 2015 No.
- anonymous (5/14) Apr 24 2015 There's also GC.free, which is also marked pure.
- deadalnix (4/21) Apr 24 2015 GC.free should probably not be pure, but that is also not at all
- Steven Schveighoffer (5/26) Apr 24 2015 I think you are thinking of @safe-ty. malloc and free can be pure, but
- deadalnix (4/8) Apr 24 2015 No, it should not be pure because it alter global state in a
- Steven Schveighoffer (7/14) Apr 24 2015 But so does GC.malloc.
- deadalnix (11/24) Apr 24 2015 No, that's the whole point of using a GC. You ask it for a chunk
- Steven Schveighoffer (6/25) Apr 24 2015 When you do ANYTHING to mutable data, you potentially alter references
- deadalnix (10/20) Apr 24 2015 OK, if you want to play that game, don't access memory ever, that
- Steven Schveighoffer (14/30) Apr 24 2015 All I'm saying is that GC.malloc alters global state. I agree that it's
- weaselcat (7/11) Apr 24 2015 A lie that is universally agreed upon is virtually
- Steven Schveighoffer (12/22) Apr 24 2015 I hadn't noticed that.
- deadalnix (5/10) Apr 25 2015 That is the whole point. See it as follow: GC.malloc create new
- Steven Schveighoffer (11/20) Apr 27 2015 I get that, you can apply the same thing for free. No reason this can't
- deadalnix (10/35) Apr 27 2015 With malloc, you have 2 new thing is userland:
- anonymous (12/19) Apr 24 2015 Ok, fair enough.
- David Nadlinger (5/9) Apr 24 2015 In case there is further confusion about purity in D, let me do a
- anonymous (5/9) Apr 24 2015 I'm pretty sure that I've read that. But I had completely
- =?UTF-8?B?Tm9yZGzDtnc=?= (16/25) Mar 31 2016 A solution is to fake purity through
- ag0aep6g (26/40) Mar 31 2016 As has been explained to me in this very thread, the fact that malloc
- deadalnix (9/49) Mar 31 2016 Is it not pure, strong or weak. GC.malloc is pure because the
- Timon Gehr (8/11) Mar 31 2016 It's the other way around. Without the "optimization" there is no way
- deadalnix (6/22) Apr 01 2016 I can see the logic. Yet, the only thing that can be returned if
- ag0aep6g (22/26) Mar 31 2016 How does malloc expose its state and GC.malloc doesn't?
- ZombineDev (19/50) Apr 01 2016 The last case is different. It has nothing to do with pure. It is
- Simen Kjaeraas (20/29) Apr 01 2016 [snip]
- =?UTF-8?B?Tm9yZGzDtnc=?= (2/5) Mar 31 2016 Got it. Sorry for the misleads. I'm tired. Gonna sleep. Thanks.
- ag0aep6g (3/8) Apr 01 2016 I've filed an issue:
GC.malloc is marked pure. But it isn't, is it? This should hold for a pure function: assert(f(x) == f(x)); This fails with GC.malloc, of course. Or consider this: auto v = f(x); auto w = f(x); When f is pure, a compiler should be free to reuse the value of v for w. That's no good with GC.malloc, obviously.
Apr 24 2015
string toLower(string s); Should that be pure? Repeated calls to it, given the same input, will return the same output, but they will also most likely be separately allocated. GC.malloc might be cheating to be pure, but it does enable a lot of more logically pure stuff on top of it...
Apr 24 2015
On 4/24/15 11:05 AM, anonymous wrote:GC.malloc is marked pure. But it isn't, is it? This should hold for a pure function: assert(f(x) == f(x));All functional make this concession -- allocating is pure as long as you don't look at the address. You a language that doesn't allow allocating memory is quite useless.This fails with GC.malloc, of course. Or consider this: auto v = f(x); auto w = f(x); When f is pure, a compiler should be free to reuse the value of v for w. That's no good with GC.malloc, obviously.This is OK as long as f is *strong* pure. D pure is not the same as the traditional definition. And GC.malloc is not strong pure, as it returns mutable data. However, this should be strong pure: immutable(int)* foo(int x) pure { return new int(x); } Any call to foo could be cached and avoided. This is allowed by the compiler (but I'm not sure if the optimization is implemented). But *inside* foo, you are allowed to call "weak" pure functions. Those calls cannot be cached. Note that calls to foo *could* be cached, but are not *required* to be cached, as you hinted in your question. -Steve
Apr 24 2015
On 4/24/15 11:21 AM, Steven Schveighoffer wrote:All functional make this concession -- allocating is pure as long as you don't look at the address. You a language that doesn't allow allocating memory is quite useless.All functional *languages* make this concession... -Steve
Apr 24 2015
On Friday, 24 April 2015 at 15:21:43 UTC, Steven Schveighoffer wrote:Any call to foo could be cached and avoided. This is allowed by the compiler (but I'm not sure if the optimization is implemented).It does, but only in the same expression, i.e. auto a = sin(x) * sin(x); // sin() is called only once but: auto a = sin(x); auto b = sin(x); // sin() is called again here
Apr 24 2015
On Friday, 24 April 2015 at 15:29:59 UTC, Marc Schütz wrote:auto a = sin(x) * sin(x); // sin() is called only onceCould you give a complete example of when this is done? Two calls here (ldc2 -c -O): real grepme(real x) pure { import std.math; auto a = sin(x) * sin(x); return a; } 0000000000000000 <_D4test6grepmeFNaeZe>: 0: 48 83 ec 28 sub rsp,0x28 4: db 6c 24 30 fld TBYTE PTR [rsp+0x30] 8: d9 c0 fld st(0) a: db 7c 24 10 fstp TBYTE PTR [rsp+0x10] e: db 3c 24 fstp TBYTE PTR [rsp] 11: e8 00 00 00 00 call 16 <_D4test6grepmeFNaeZe+0x16> 16: db 7c 24 1c fstp TBYTE PTR [rsp+0x1c] 1a: db 6c 24 10 fld TBYTE PTR [rsp+0x10] 1e: db 3c 24 fstp TBYTE PTR [rsp] 21: e8 00 00 00 00 call 26 <_D4test6grepmeFNaeZe+0x26> 26: db 6c 24 1c fld TBYTE PTR [rsp+0x1c] 2a: de c9 fmulp st(1),st 2c: 48 83 c4 28 add rsp,0x28 30: c3 ret
Apr 24 2015
On Friday, 24 April 2015 at 16:34:09 UTC, anonymous wrote:On Friday, 24 April 2015 at 15:29:59 UTC, Marc Schütz wrote:Hmm... strange. I was convinced it worked that way. I used `sin()` specifically because I remember I've seen an example with it. But now I can't get it do work anymore, not even with `int` or a user-defined pure function.auto a = sin(x) * sin(x); // sin() is called only onceCould you give a complete example of when this is done? Two calls here (ldc2 -c -O): real grepme(real x) pure { import std.math; auto a = sin(x) * sin(x); return a; } 0000000000000000 <_D4test6grepmeFNaeZe>: 0: 48 83 ec 28 sub rsp,0x28 4: db 6c 24 30 fld TBYTE PTR [rsp+0x30] 8: d9 c0 fld st(0) a: db 7c 24 10 fstp TBYTE PTR [rsp+0x10] e: db 3c 24 fstp TBYTE PTR [rsp] 11: e8 00 00 00 00 call 16 <_D4test6grepmeFNaeZe+0x16> 16: db 7c 24 1c fstp TBYTE PTR [rsp+0x1c] 1a: db 6c 24 10 fld TBYTE PTR [rsp+0x10] 1e: db 3c 24 fstp TBYTE PTR [rsp] 21: e8 00 00 00 00 call 26 <_D4test6grepmeFNaeZe+0x26> 26: db 6c 24 1c fld TBYTE PTR [rsp+0x1c] 2a: de c9 fmulp st(1),st 2c: 48 83 c4 28 add rsp,0x28 30: c3 ret
Apr 24 2015
On Friday, 24 April 2015 at 15:21:43 UTC, Steven Schveighoffer wrote:This is OK as long as f is *strong* pure. D pure is not the same as the traditional definition. And GC.malloc is not strong pure, as it returns mutable data.Ah, this is the piece I was missing. I was aware of weak/strong pure, but I didn't know the return type plays a role in that. Could core.stdc.stdlib.malloc and friends also be marked pure then?
Apr 24 2015
On 4/24/15 11:43 AM, anonymous wrote:On Friday, 24 April 2015 at 15:21:43 UTC, Steven Schveighoffer wrote:IMO, yes. But not everyone agrees with that. Definitely, free has issues with being pure. And if free cannot be pure, there's not much point in making malloc pure. But I could see something like RefCounted that uses malloc being pure. -SteveThis is OK as long as f is *strong* pure. D pure is not the same as the traditional definition. And GC.malloc is not strong pure, as it returns mutable data.Ah, this is the piece I was missing. I was aware of weak/strong pure, but I didn't know the return type plays a role in that. Could core.stdc.stdlib.malloc and friends also be marked pure then?
Apr 24 2015
On Friday, 24 April 2015 at 15:43:17 UTC, anonymous wrote:On Friday, 24 April 2015 at 15:21:43 UTC, Steven Schveighoffer wrote:No. Allocating on the GC is "stateless" as the GC will handle the state by itself, from the program perspective, there is no state to maintain. malloc require free, and the state management is pushed on the application rather than the runtime. It is not pure.This is OK as long as f is *strong* pure. D pure is not the same as the traditional definition. And GC.malloc is not strong pure, as it returns mutable data.Ah, this is the piece I was missing. I was aware of weak/strong pure, but I didn't know the return type plays a role in that. Could core.stdc.stdlib.malloc and friends also be marked pure then?
Apr 24 2015
On Friday, 24 April 2015 at 17:07:20 UTC, deadalnix wrote:On Friday, 24 April 2015 at 15:43:17 UTC, anonymous wrote:[...]There's also GC.free, which is also marked pure. I can't see how GC.malloc followed by GC.free is more pure than stdlib malloc followed by stdlib free.Could core.stdc.stdlib.malloc and friends also be marked pure then?No. Allocating on the GC is "stateless" as the GC will handle the state by itself, from the program perspective, there is no state to maintain. malloc require free, and the state management is pushed on the application rather than the runtime. It is not pure.
Apr 24 2015
On Friday, 24 April 2015 at 17:45:57 UTC, anonymous wrote:On Friday, 24 April 2015 at 17:07:20 UTC, deadalnix wrote:GC.free should probably not be pure, but that is also not at all what you talk about in previous posts, which led me to think you are essentially doing a stunt as to not admit you were wrong.On Friday, 24 April 2015 at 15:43:17 UTC, anonymous wrote:[...]There's also GC.free, which is also marked pure. I can't see how GC.malloc followed by GC.free is more pure than stdlib malloc followed by stdlib free.Could core.stdc.stdlib.malloc and friends also be marked pure then?No. Allocating on the GC is "stateless" as the GC will handle the state by itself, from the program perspective, there is no state to maintain. malloc require free, and the state management is pushed on the application rather than the runtime. It is not pure.
Apr 24 2015
On 4/24/15 1:57 PM, deadalnix wrote:On Friday, 24 April 2015 at 17:45:57 UTC, anonymous wrote:I think you are thinking of safe-ty. malloc and free can be pure, but must be contained properly. purity when it comes to mutable data is a tricky thing. -SteveOn Friday, 24 April 2015 at 17:07:20 UTC, deadalnix wrote:GC.free should probably not be pure, but that is also not at all what you talk about in previous posts, which led me to think you are essentially doing a stunt as to not admit you were wrong.On Friday, 24 April 2015 at 15:43:17 UTC, anonymous wrote:[...]There's also GC.free, which is also marked pure. I can't see how GC.malloc followed by GC.free is more pure than stdlib malloc followed by stdlib free.Could core.stdc.stdlib.malloc and friends also be marked pure then?No. Allocating on the GC is "stateless" as the GC will handle the state by itself, from the program perspective, there is no state to maintain. malloc require free, and the state management is pushed on the application rather than the runtime. It is not pure.
Apr 24 2015
On Friday, 24 April 2015 at 18:48:43 UTC, Steven Schveighoffer wrote:I think you are thinking of safe-ty. malloc and free can be pure, but must be contained properly. purity when it comes to mutable data is a tricky thing. -SteveNo, it should not be pure because it alter global state in a manner visible to the program.
Apr 24 2015
On 4/24/15 3:12 PM, deadalnix wrote:On Friday, 24 April 2015 at 18:48:43 UTC, Steven Schveighoffer wrote:But so does GC.malloc. In any case, it's already been stated by Walter/Andrei that they are not interested in making C malloc/free pure. So it's a moot issue to argue over. This likely will come up again when std.allocator is completed, and we can re-examine it then. -SteveI think you are thinking of safe-ty. malloc and free can be pure, but must be contained properly. purity when it comes to mutable data is a tricky thing.No, it should not be pure because it alter global state in a manner visible to the program.
Apr 24 2015
On Friday, 24 April 2015 at 19:41:21 UTC, Steven Schveighoffer wrote:On 4/24/15 3:12 PM, deadalnix wrote:No, that's the whole point of using a GC. You ask it for a chunk of memory, it gives you a chunk of memory. This does not affect any other part of your program as it is a NEW chunk of memory, so you are not messing with your program state. When you free, you potentially alter references anywhere outside your "pure" function. It must not be pure. Obviously, there is state involved inside the GC, but the whole point is that it is isolated from the program (granted the GC is not buggy).On Friday, 24 April 2015 at 18:48:43 UTC, Steven Schveighoffer wrote:But so does GC.malloc.I think you are thinking of safe-ty. malloc and free can be pure, but must be contained properly. purity when it comes to mutable data is a tricky thing.No, it should not be pure because it alter global state in a manner visible to the program.
Apr 24 2015
On 4/24/15 4:42 PM, deadalnix wrote:On Friday, 24 April 2015 at 19:41:21 UTC, Steven Schveighoffer wrote:But I can check memory usage size and see global state has been altered.On 4/24/15 3:12 PM, deadalnix wrote:No, that's the whole point of using a GC. You ask it for a chunk of memory, it gives you a chunk of memory. This does not affect any other part of your program as it is a NEW chunk of memory, so you are not messing with your program state.On Friday, 24 April 2015 at 18:48:43 UTC, Steven Schveighoffer wrote:But so does GC.malloc.I think you are thinking of safe-ty. malloc and free can be pure, but must be contained properly. purity when it comes to mutable data is a tricky thing.No, it should not be pure because it alter global state in a manner visible to the program.When you free, you potentially alter references anywhere outside your "pure" function. It must not be pure.When you do ANYTHING to mutable data, you potentially alter references outside your pure function. This is not a disqualifier. It's accessing global sate directly that wasn't passed to you that is a disqualifier. -Steve
Apr 24 2015
On Friday, 24 April 2015 at 20:55:02 UTC, Steven Schveighoffer wrote:But I can check memory usage size and see global state has been altered.OK, if you want to play that game, don't access memory ever, that is global state. I mean, even if the memory is read only you may end up affecting the MMU, so that is definitively a no go. Also, you'd better have only a one instruction loop in your program as otherwise you'll affect the program counter, a definitively visible state from the user.pure function can access global immutable state that wasn't passed to it, so you may want to revise your definition.When you free, you potentially alter references anywhere outside your "pure" function. It must not be pure.When you do ANYTHING to mutable data, you potentially alter references outside your pure function. This is not a disqualifier. It's accessing global sate directly that wasn't passed to you that is a disqualifier. -Steve
Apr 24 2015
On 4/24/15 5:07 PM, deadalnix wrote:On Friday, 24 April 2015 at 20:55:02 UTC, Steven Schveighoffer wrote:All I'm saying is that GC.malloc alters global state. I agree that it's OK to pretend that it doesn't because as long as you agree not to base things on this knowledge, you are fine calling pure functions that use GC. It's possible to do things like this, to make pure functions "unpure": bool foo() pure { return new int(0) < new int(0); } We just agree to ignore that aspect. And I'm OK with it. As I'm OK with ignoring the bad things you can do with C malloc or C free that make things impure.But I can check memory usage size and see global state has been altered.OK, if you want to play that game, don't access memory ever, that is global state. I mean, even if the memory is read only you may end up affecting the MMU, so that is definitively a no go. Also, you'd better have only a one instruction loop in your program as otherwise you'll affect the program counter, a definitively visible state from the user.Sure: s/accessing/altering, my mistake. -Stevepure function can access global immutable state that wasn't passed to it, so you may want to revise your definition.When you free, you potentially alter references anywhere outside your "pure" function. It must not be pure.When you do ANYTHING to mutable data, you potentially alter references outside your pure function. This is not a disqualifier. It's accessing global sate directly that wasn't passed to you that is a disqualifier.
Apr 24 2015
On Friday, 24 April 2015 at 23:27:36 UTC, Steven Schveighoffer wrote:All I'm saying is that GC.malloc alters global state. I agree that it's OK to pretend that it doesn't because as long as you agree not to base things on this knowledge, you are fine calling pure functions that use GC.A lie that is universally agreed upon is virtually indistinguishable from the truth. the reasons against making malloc/free pure are very... thin. Walter himself attempted to make them pure only last week(!) https://github.com/D-Programming-Language/druntime/pull/1221
Apr 24 2015
On 4/24/15 8:30 PM, weaselcat wrote:On Friday, 24 April 2015 at 23:27:36 UTC, Steven Schveighoffer wrote:I hadn't noticed that. And linked from there is the reason I was shown that free cannot be pure (from a while ago): void freeIt(immutable(int)* x) pure { free(cast(int *)x); } A compiler could legally just not even call this function. It's a pretty compelling reason. I have a feeling that we can't make free generally pure. When needed, it will have to be hacked somehow in a controlled way. Or we could make some rule that you should never cast immutable pointers to mutable in order to free them. Doesn't sound very enforceable... -SteveAll I'm saying is that GC.malloc alters global state. I agree that it's OK to pretend that it doesn't because as long as you agree not to base things on this knowledge, you are fine calling pure functions that use GC.A lie that is universally agreed upon is virtually indistinguishable from the truth. the reasons against making malloc/free pure are very... thin. Walter himself attempted to make them pure only last week(!) https://github.com/D-Programming-Language/druntime/pull/1221
Apr 24 2015
On Friday, 24 April 2015 at 23:27:36 UTC, Steven Schveighoffer wrote:That is the whole point. See it as follow: GC.malloc create new state. As long as this new state doesn't escape the pure function, it is as if that state was local.pure function can access global immutable state that wasn't passed to it, so you may want to revise your definition.Sure: s/accessing/altering, my mistake. -Steve
Apr 25 2015
On 4/25/15 11:06 PM, deadalnix wrote:On Friday, 24 April 2015 at 23:27:36 UTC, Steven Schveighoffer wrote:I get that, you can apply the same thing for free. No reason this can't be a pure function: void foo() { int *x = cast(int *)malloc(sizeof(int)); *x = 0; scope(exit) free(x); } But there are other problems, as I pointed out in another post. -SteveThat is the whole point. See it as follow: GC.malloc create new state. As long as this new state doesn't escape the pure function, it is as if that state was local.pure function can access global immutable state that wasn't passed to it, so you may want to revise your definition.Sure: s/accessing/altering, my mistake.
Apr 27 2015
On Monday, 27 April 2015 at 10:50:12 UTC, Steven Schveighoffer wrote:On 4/25/15 11:06 PM, deadalnix wrote:With malloc, you have 2 new thing is userland: - A new state, which, as for the GC case could be considered pure. - A global state that you have to maintain (the fact that you allocated and must free) and this should not be pure.On Friday, 24 April 2015 at 23:27:36 UTC, Steven Schveighoffer wrote:I get that, you can apply the same thing for free. No reason this can't be a pure function:That is the whole point. See it as follow: GC.malloc create new state. As long as this new state doesn't escape the pure function, it is as if that state was local.pure function can access global immutable state that wasn't passed to it, so you may want to revise your definition.Sure: s/accessing/altering, my mistake.void foo() { int *x = cast(int *)malloc(sizeof(int)); *x = 0; scope(exit) free(x); } But there are other problems, as I pointed out in another post. -SteveIn that specific use case, I think this is fair to consider that code pure, or at least pretend it is. D being a system programming language, you can pretend this is pure.
Apr 27 2015
On Friday, 24 April 2015 at 17:57:12 UTC, deadalnix wrote:On Friday, 24 April 2015 at 17:45:57 UTC, anonymous wrote:[...]Ok, fair enough. Right now, I'd lean the other way and make stdlib free pure, too. Both free variants essentially invalidate their void* arguments. (Weakly) pure functions may tinker with their arguments, so that could be fine. I'm probably missing something, though. Feel free to enlighten me.I can't see how GC.malloc followed by GC.free is more pure than stdlib malloc followed by stdlib free.GC.free should probably not be pure,but that is also not at all what you talk about in previous posts, which led me to think you are essentially doing a stunt as to not admit you were wrong.Huh? I had missed that GC.malloc isn't strongly pure but weakly pure because the return type. I don't mean to deny that or distract from it. If it helps: I was wrong. My shame is great. Please forgive my ignorance.
Apr 24 2015
On Friday, 24 April 2015 at 15:05:15 UTC, anonymous wrote:auto v = f(x); auto w = f(x); When f is pure, a compiler should be free to reuse the value of v for w. That's no good with GC.malloc, obviously.In case there is further confusion about purity in D, let me do a shameless plug for an article I wrote a couple of years back: http://klickverbot.at/blog/2012/05/purity-in-d/ — David
Apr 24 2015
On Friday, 24 April 2015 at 18:03:50 UTC, David Nadlinger wrote:In case there is further confusion about purity in D, let me do a shameless plug for an article I wrote a couple of years back: http://klickverbot.at/blog/2012/05/purity-in-d/ — DavidI'm pretty sure that I've read that. But I had completely forgotten about the "Indirections in the Return Type?" part which covers exactly the scenario I was worried about. So, yeah, good article. Sorry for the noise.
Apr 24 2015
On Friday, 24 April 2015 at 15:05:15 UTC, anonymous wrote:GC.malloc is marked pure. But it isn't, is it? This should hold for a pure function: assert(f(x) == f(x)); This fails with GC.malloc, of course. Or consider this: auto v = f(x); auto w = f(x); When f is pure, a compiler should be free to reuse the value of v for w. That's no good with GC.malloc, obviously.A solution is to fake purity through extern(C) pure nothrow system nogc { void* malloc(size_t size); void* realloc(void* ptr, size_t size); void free(void* ptr); } Pay attention to the use of malloc() though. Note that this makes malloc() strongly pure (its single parameters is passed by value). Therefore successive calls to malloc() with the same argument will be optimized away and all those calls will return the same values as the first call. When used in allocators this shouldn't be a problem, though. Used successfully at https://github.com/nordlow/justd/blob/master/packedarray.d#L6
Mar 31 2016
On 31.03.2016 23:25, Nordlöw wrote:A solution is to fake purity through extern(C) pure nothrow system nogc { void* malloc(size_t size); void* realloc(void* ptr, size_t size); void free(void* ptr); } Pay attention to the use of malloc() though. Note that this makes malloc() strongly pure (its single parameters is passed by value).As has been explained to me in this very thread, the fact that malloc returns a pointer to mutable data makes it not strongly pure. See http://klickverbot.at/blog/2012/05/purity-in-d/#indirections-in-the-return-typeTherefore successive calls to malloc() with the same argument will be optimized away and all those calls will return the same values as the first call. When used in allocators this shouldn't be a problem, though.Uh, as far as I see, that would be catastrophic. I feel like I must be missing something here again, but it looks like dmd actually gets this wrong: ---- extern(C) void* malloc(size_t size) pure nothrow; void main() { auto a = cast(ubyte*) malloc(1); auto b = cast(ubyte*) malloc(1); import std.stdio; writeln(a is b); /* should be false */ *a = 1; *b = 2; writeln(*a); /* should be 1 */ } ---- Compiled with dmd and no optimization switches, this prints "false" and "1" as expected. Compiled with `dmd -O -release`, this prints "true" and "2". The heck? With `ldc2 -O5 -release`: "false" and "1". No problem there. This looks like a serious bug in dmd to me.
Mar 31 2016
On Thursday, 31 March 2016 at 22:18:03 UTC, ag0aep6g wrote:On 31.03.2016 23:25, Nordlöw wrote:Is it not pure, strong or weak. GC.malloc is pure because the memory is going to be garbage collected. malloc is not pure as the memory need to be freed. The state in the allocator is exposed to the program.A solution is to fake purity through extern(C) pure nothrow system nogc { void* malloc(size_t size); void* realloc(void* ptr, size_t size); void free(void* ptr); } Pay attention to the use of malloc() though. Note that this makes malloc() strongly pure (its single parameters is passed by value).As has been explained to me in this very thread, the fact that malloc returns a pointer to mutable data makes it not strongly pure.Uh, as far as I see, that would be catastrophic. I feel like I must be missing something here again, but it looks like dmd actually gets this wrong: ---- extern(C) void* malloc(size_t size) pure nothrow; void main() { auto a = cast(ubyte*) malloc(1); auto b = cast(ubyte*) malloc(1); import std.stdio; writeln(a is b); /* should be false */ *a = 1; *b = 2; writeln(*a); /* should be 1 */ } ---- Compiled with dmd and no optimization switches, this prints "false" and "1" as expected. Compiled with `dmd -O -release`, this prints "true" and "2". The heck? With `ldc2 -O5 -release`: "false" and "1". No problem there. This looks like a serious bug in dmd to me.Lie to the compiler and it will punish you for it. DMD optimizes malloc because the only reason it would have to return a different pointer would be internal state (and in fact, it indeed has internal state).
Mar 31 2016
On 01.04.2016 00:52, deadalnix wrote:DMD optimizes malloc because the only reason it would have to return a different pointer would be internal state (and in fact, it indeed has internal state).It's the other way around. Without the "optimization" there is no way for a 'pure' function to return a reference to the same mutable memory block independent of its arguments more than once. In the end it is up to the spec, but IMO compiler optimizations should not be able to introduce mutable aliasing that was not there before. (Even for immutable references, sharing the same result is moot, as D supports checking for reference equality.)
Mar 31 2016
On Friday, 1 April 2016 at 01:19:01 UTC, Timon Gehr wrote:On 01.04.2016 00:52, deadalnix wrote:I can see the logic. Yet, the only thing that can be returned if no state is exposed is either a constant or something computed from 1 (cast(void*) 1). But yeah, the optimization should probably not be done if the return type is mutable.DMD optimizes malloc because the only reason it would have to return a different pointer would be internal state (and in fact, it indeed has internal state).It's the other way around. Without the "optimization" there is no way for a 'pure' function to return a reference to the same mutable memory block independent of its arguments more than once. In the end it is up to the spec, but IMO compiler optimizations should not be able to introduce mutable aliasing that was not there before. (Even for immutable references, sharing the same result is moot, as D supports checking for reference equality.)
Apr 01 2016
On 01.04.2016 00:52, deadalnix wrote:Is it not pure, strong or weak. GC.malloc is pure because the memory is going to be garbage collected. malloc is not pure as the memory need to be freed. The state in the allocator is exposed to the program.How does malloc expose its state and GC.malloc doesn't? * They have the same signature. Both return pointers (to mutable data). * malloc has free, GC.malloc has GC.free. So you can manually free the memory in both cases. * You don't have to free memory from malloc. You can let it leak.Lie to the compiler and it will punish you for it.This also happens with functions that have an implementation in source: ---- int[] f() pure nothrow {return [0];} void main() { auto a = f(); auto b = f(); a[0] = 1; b[0] = 2; import std.stdio; writeln(a is b); /* should be false */ writeln(a[0]); /* should be 1 */ } ---- Prints "true" and "2" when compiled with `dmd -O -release`. So I don't think that lying to the compiler is the problem here.
Mar 31 2016
On Friday, 1 April 2016 at 05:00:43 UTC, ag0aep6g wrote:On 01.04.2016 00:52, deadalnix wrote:The last case is different. It has nothing to do with pure. It is about reference-type literals and default field values: class C { int x; } struct S { C c = new C; int[] arr = [1, 2, 3]; } S s1, s2; assert (s1.arr is s2.arr); assert (s1.c is s2.c); immutable S s3; s1.arr[0] = 42; s1.c.x = 24; assert (s2.arr[0] == 42); assert (s3.arr[0] == 42); assert (s2.c.x == 24); assert (s3.c.x == 24);Is it not pure, strong or weak. GC.malloc is pure because the memory is going to be garbage collected. malloc is not pure as the memory need to be freed. The state in the allocator is exposed to the program.How does malloc expose its state and GC.malloc doesn't? * They have the same signature. Both return pointers (to mutable data). * malloc has free, GC.malloc has GC.free. So you can manually free the memory in both cases. * You don't have to free memory from malloc. You can let it leak.Lie to the compiler and it will punish you for it.This also happens with functions that have an implementation in source: ---- int[] f() pure nothrow {return [0];} void main() { auto a = f(); auto b = f(); a[0] = 1; b[0] = 2; import std.stdio; writeln(a is b); /* should be false */ writeln(a[0]); /* should be 1 */ } ---- Prints "true" and "2" when compiled with `dmd -O -release`. So I don't think that lying to the compiler is the problem here.
Apr 01 2016
On Friday, 1 April 2016 at 07:58:46 UTC, ZombineDev wrote:On Friday, 1 April 2016 at 05:00:43 UTC, ag0aep6g wrote:[snip]int[] f() pure nothrow {return [0];}The last case is different. It has nothing to do with pure. It is about reference-type literals and default field values:[snip]struct S { C c = new C; int[] arr = [1, 2, 3]; }No. Try this: int[] bar() { return [0]; } void main() { auto a = bar(); a[0] = 3; auto b = bar(); assert(b[0] == 0); } That assert passes with flying colors no matter the compiler flags. It is true that arrays in structs' initial state are copied (and may lead to subtle bugs), but the same is not the case for arrays returned from functions. -- Simen
Apr 01 2016
On Thursday, 31 March 2016 at 22:18:03 UTC, ag0aep6g wrote:As has been explained to me in this very thread, the fact that malloc returns a pointer to mutable data makes it not strongly pure.Got it. Sorry for the misleads. I'm tired. Gonna sleep. Thanks.
Mar 31 2016
On 01.04.2016 00:18, ag0aep6g wrote:Compiled with dmd and no optimization switches, this prints "false" and "1" as expected. Compiled with `dmd -O -release`, this prints "true" and "2". The heck? With `ldc2 -O5 -release`: "false" and "1". No problem there. This looks like a serious bug in dmd to me.I've filed an issue: https://issues.dlang.org/show_bug.cgi?id=15862
Apr 01 2016