June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #40 from Denis Shelomovskij <verylonglogin.reg@gmail.com> 2012-06-04 20:27:24 MSD --- (In reply to comment #36) > > int f(size_t) pure; > > > __gshared int tmp; > > void g(size_t, ref int dummy = tmp) pure; > > > void h(size_t a, size_t b) pure > > { > > int res = f(a); > > g(b); > > assert(res == f(a)); // may fail, no guaranties by language! > >} > > Your g(b) causes h to be impure, because it accesses tmp, which is __gshared. Yes, my mistake. Lets call "g(b, b)". > Also, as far as eliding additional calls to pure functions, at present, they only occur within the same line, and I think that may only ever occur within the same expression (it's either expression or statement, I'm not sure which). So, the eliding of additional pure function calls is going to be quite rare. The _primary_ benefit of pure is how it enables you to reason about your code. You _know_ that f doesn't mess with anything other than the argument that you passed to it without having to look at its body at all. No, because the assert may not pass. See below. > Oh, and the assertion _is_ guaranteed to pass. a and res are both value types. Neither res nor a are passed to anything or accessed in any way other than in the the lines with the calls to f, and even if g were impure, and it screwed with whatever argument was passed as the first argument to the h call, it wouldn't be able to mess with the value of a, because it was already copied. Again, assert may not pass. Were it pass, I will not write this question. Example: --- int f(size_t p) pure { return *cast(int*) p; } void g(size_t p, ref size_t) pure { ++*cast(int*) p; } void h(size_t a, size_t b) pure { int res = f(a); g(b, b); assert(res == f(a)); // may fail, no guaranties by language! } void main() { int a; h(cast(size_t) &a, cast(size_t) &a); } --- -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #41 from Jonathan M Davis <jmdavisProg@gmx.com> 2012-06-04 09:35:33 PDT --- > void g(size_t p, ref size_t) pure >{ > ++*cast(int*) p; >} You're casting a size_t to a pointer. That's breaking the type system. The assertion is guaranteed to pass as long as you don't break the type system. That's exactly the same as occurs when casting away const. When you subvert the type system, the compiler can't guarantee anything. It's the _programmer's_ job at that point to maintain the compiler's guarantees. The compiler is free to assume that the programmer did not violate those guarantees. If you do, you've created a bug. This is precisely the sort of thing that comes up when someone is crazy enough to cast away const on somethnig and try and mutate it. Such an example is ultimately irrelevant, precisely because it violates the type system. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #42 from Denis Shelomovskij <verylonglogin.reg@gmail.com> 2012-06-04 20:52:56 MSD --- (In reply to comment #41) > > void g(size_t p, ref size_t) pure > >{ > > ++*cast(int*) p; > >} > > You're casting a size_t to a pointer. That's breaking the type system. The assertion is guaranteed to pass as long as you don't break the type system. That's exactly the same as occurs when casting away const. It isn't and here is the point! It's explicitly stated that when I'm casting away const and than modify date the result is undefined. I will be happy if I'm missing that this casting results in undefined result too. > When you subvert the > type system, the compiler can't guarantee anything. It's the _programmer's_ job > at that point to maintain the compiler's guarantees. The compiler is free to > assume that the programmer did not violate those guarantees. No it's not. Otherwise every such break of the rules will result in undefined behavior. E.g. C++ have strict aliasing and can shrink what function arguments can refer to and if C++ program has `strlen` source it can inline and move it out of loop if, e.g. in loop we only modify and `int*`, but in D it can't be done because every `int*` can refer to every `char*`. So C++ support pure functions better than D. :) > If you do, you've > created a bug. This is precisely the sort of thing that comes up when someone > is crazy enough to cast away const on somethnig and try and mutate it. Such an > example is ultimately irrelevant, precisely because it violates the type > system. Every @system function can do it. It can even be written in assembly language. I'm just saying here that it doesn't violate definition of a `pure` function and here is the problem. I will be happy once it will violate the definition. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #43 from Steven Schveighoffer <schveiguy@yahoo.com> 2012-06-04 10:30:19 PDT --- (In reply to comment #42) > It isn't and here is the point! It's explicitly stated that when I'm casting away const and than modify date the result is undefined. I will be happy if I'm missing that this casting results in undefined result too. I believe it is undefined to cast a size_t to a pointer and use it as a pointer. But I could be wrong. In any case, pure function optimizations do not conservatively assume you will be doing that -- the compiler will optimize assuming you do *not* use it as a pointer. Whenever you cast, you are telling the compiler "I know what I'm doing." At that point, you are on your own as far as guaranteeing type safety and pure functions are actually pure. > No it's not. Otherwise every such break of the rules will result in undefined behavior. E.g. C++ have strict aliasing and can shrink what function arguments can refer to and if C++ program has `strlen` source it can inline and move it out of loop if, e.g. in loop we only modify and `int*`, but in D it can't be done because every `int*` can refer to every `char*`. So C++ support pure functions better than D. :) If you don't want the compiler to make bad optimization decisions, then don't use casting. At best, this will be implementation defined. I think you are way overthinking this. D's compiler and optimizer are based on a C++ compiler, written by the same person. Most of the same rules from C++ apply to D. The compiler does not "assume the worst," it "assumes the reasonable," until you tell it otherwise. In other words, no reasonable developer will write code like you have, so the compiler assumes you are reasonable. Using toy examples to show how the compiler *must* behave does not work. Yes, maybe this isn't spelled out fully in the spec, and it should be. But you are coming at this problem from the wrong end, start with what the compiler acutally *does*, not what you *think it should do* based on the spec. The spec, like most software products, is usually the last to be updated when it comes to additional features, and the new pure rules are quite recent. The priority of "who is right" goes like this: 1. TDPL (the book) 2. The reference implementation (DMD) 3. dlang.org -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #44 from Steven Schveighoffer <schveiguy@yahoo.com> 2012-06-04 10:45:33 PDT --- (In reply to comment #7) > In general response to this bug, I'm unsure how pointers should be treated by the optimizer. My gut feeling is the compiler/optimizer should trust the code "knows what it's doing." and so should expect that the code implicitly knows how much data it can access after the pointer. After thinking about this for a couple days (and watching the emails pour in with differing opinions), here is what I think pure functions with pointers should mean: For @system or @trusted functions, the definition of what data the pointer has access to is defined by the programmer, and not expressed in possible way to the type system or the compiler. In other words, if I have a pointer to something, the actual data referenced includes any number of bytes before or after the memory pointed at. The scope of that data is defined by the programmer of the function/type, and should be clearly documented to the user of the function. For @safe functions, the compiler should allow access only to the specific item pointed to as defined by the pointed-at type, and nothing else (pointer math is disallowed, pointer indexing is disallowed, and casting is disallowed). For pure functions, no conservative assumptions should be made or acted upon during optimizations that expect the function has access to global data. In other words, a @system pure function that accepts a pointer should rightly assume that the function does *not* access global data, and that whatever data the function accesses via its pointer was passed via its parameter as expected by the caller. If the function incorrectly accesses global data via its pointer, then it results in undefined behavior. These expectations and behaviors should be spelled out in the spec. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #45 from klickverbot <code@klickverbot.at> 2012-06-04 10:51:45 PDT --- (In reply to comment #44) Still thinking about the rest of the proposal, but: > […] or @trusted functions […] If a @trusted function accepts a pointer, it must _under no circumstances_ access anything except for the pointer target, because it can be called from @safe code. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #46 from Steven Schveighoffer <schveiguy@yahoo.com> 2012-06-04 10:59:49 PDT --- (In reply to comment #45) > (In reply to comment #44) > Still thinking about the rest of the proposal, but: > > > […] or @trusted functions […] > If a @trusted function accepts a pointer, it must _under no circumstances_ access anything except for the pointer target, because it can be called from @safe code. The point of @trusted is that it is treated as @safe, but can do unsafe things. At that point, you are telling the compiler that you know better than it does that the code is safe. The compiler is going to assume you did not access anything else beyond the target, so you have to keep that in mind when writing a @trusted function that accepts a pointer parameter. Off the top of my head, I can't think of any valid usage of this, but it doesn't mean we should necessarily put a restriction on @trusted functions. This is a systems language, and @trusted is a tool used to circumvent @safe-ty when you know it is actually @safe. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #47 from Denis Shelomovskij <verylonglogin.reg@gmail.com> 2012-06-04 22:13:05 MSD --- (In reply to comment #43) > The compiler does not "assume the worst," it "assumes the reasonable," until you tell it otherwise. In other words, no reasonable developer will write code like you have, so the compiler assumes you are reasonable. Using toy examples to show how the compiler *must* behave does not work. Common! System language must have strict rights. You just have said that D is JavaScript. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #48 from klickverbot <code@klickverbot.at> 2012-06-04 11:24:10 PDT --- (In reply to comment #46) > (In reply to comment #45) > > If a @trusted function accepts a pointer, it must _under no circumstances_ access anything except for the pointer target, because it can be called from @safe code. > > The point of @trusted is that it is treated as @safe, but can do unsafe things. > At that point, you are telling the compiler that you know better than it does > that the code is safe. > > The compiler is going to assume you did not access anything else beyond the target, so you have to keep that in mind when writing a @trusted function that accepts a pointer parameter. > > Off the top of my head, I can't think of any valid usage of this, but it doesn't mean we should necessarily put a restriction on @trusted functions. This is a systems language, and @trusted is a tool used to circumvent @safe-ty when you know it is actually @safe. Sorry, but I think you got this wrong. Consider this example: --- void gun(int* a) @trusted; int fun() @safe { auto val = new int; gun(val); return *val; } --- Here, calling gun needs to be safe under _any_ circumstances. Thus, the only memory location which gun is allowed to access is val. If it does so by evaluating *(a + k), where k = (catalanNumber(5) - meaningOfLife()), that's fine, it's @trusted, but ultimately k must always be zero. Otherwise, it might violate the memory safety guarantees that need to hold for fun(). This is definitely not »defined by the programmer, and not expressed in possible way to the type system or the compiler«. Makes sense? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
June 04, 2012 [Issue 8185] Pure functions and pointers | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | http://d.puremagic.com/issues/show_bug.cgi?id=8185 --- Comment #49 from art.08.09@gmail.com 2012-06-04 11:29:39 PDT --- As this discussions was mostly about what *should* be happening, I decided to see what actually *is* happening right now. It seems that the compiler will only optimize based on "pureness" if a function takes an 'immutable T*' argument, even 'immutable(T)*' is enough to turn the optimization off. So, right now, it is extremely conservative - and there is no bug in the implementation. (accessing mutable data via an immutable pointer can be done, but would be clearly illegal, just as using a cast) But that also means that a lot of valid optimizations aren't done, making purity significantly less useful than it could be. Basically, only functions that don't take any (non-immutable) references as arguments can benefit from "pure". But it also means D can still be incrementally fixed, as long as a sane definition of function purity is used. But this bug is a spec issue, hence probably INVALID, as there is no specification. Sorry for the noise. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
Copyright © 1999-2021 by the D Language Foundation