Thread overview | ||||||
---|---|---|---|---|---|---|
|
July 04, 2012 Pure functions and pointers (yes, again) | ||||
---|---|---|---|---|
| ||||
Since issue 8185 has been closed, I'm still very confused. I just understood that endless discussion doesn't result in anything. See example from http://d.puremagic.com/issues/show_bug.cgi?id=8185#c40 --- 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); } --- Jonathan M Davis (whose documentation correcting pull closed the issue) told me that this code result in undefined behaviour. What _exectly_ language rule this violates? I don't see this rule, but if there is no such rule, how can we treat anything as strongly pure function? -- Денис В. Шеломовский Denis V. Shelomovskij |
July 04, 2012 Re: Pure functions and pointers (yes, again) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | On Wednesday, July 04, 2012 11:59:10 Denis Shelomovskij wrote:
> Since issue 8185 has been closed, I'm still very confused. I just understood that endless discussion doesn't result in anything.
>
> See example from http://d.puremagic.com/issues/show_bug.cgi?id=8185#c40
> ---
> 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);
> }
> ---
>
> Jonathan M Davis (whose documentation correcting pull closed the issue) told me that this code result in undefined behaviour. What _exectly_ language rule this violates? I don't see this rule, but if there is no such rule, how can we treat anything as strongly pure function?
You're violating the type system. You've claimed that a size_t is a pointer by casting it to one and then operating on it as if it were one. Whether the value was originally a pointer or not is irrelevant. You've lied to the compiler about the type, which means that you've subverted the type system, and it's up to _you_ to guarantee that the guarantees that the compiler is supposed to be making hold. The compiler has to use the type system to make its gurantees, so if you lie to it about types, it will make incorrect assumptions, you'll end up with wrong code, and it'll be your fault.
It's like with const. Don't cast away const and then modify the variable. It's undefined behavior. Don't do it. You're lying to the compiler about types, and it bases its guarantees on types. So, if you've lied to it, _of course_ it's going to break.
D is a systems language, so you can do really dirty things in @system code if you need to, but don't expect the compiler to magically figure out what you're doing when you're lying to it through casts.
- Jonathan M Davis
|
July 04, 2012 Re: Pure functions and pointers (yes, again) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Denis Shelomovskij | Denis Shelomovskij , dans le message (digitalmars.D:171072), a écrit :
> Since issue 8185 has been closed, I'm still very confused. I just understood that endless discussion doesn't result in anything.
>
> See example from http://d.puremagic.com/issues/show_bug.cgi?id=8185#c40
> ---
> 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);
> }
> ---
>
> Jonathan M Davis (whose documentation correcting pull closed the issue) told me that this code result in undefined behaviour. What _exectly_ language rule this violates? I don't see this rule, but if there is no such rule, how can we treat anything as strongly pure function?
Casting a value to a pointer clearly subvert the type system. A value with no reference (like size_t) is convertible to immutable, but a pointer cannot. Thus, a function with f's signature is strongly pure, but it is not if takes an int*. That's how you can create a bug.
The same issue occurs if you 'create' a pointer by illegal pointer arithmetic for instance: this is undefined behavior. Creating and using any kind reference by casting is undefined. That's not only a purity problem, it is a safety, a garbage collection, an and optimisation issue. In your case, you know what you ar doing regarding safety and garbage collection. Fine. But you do not respect optimisations linked with purity. Too bad, you can't ignore that the compiler is going to make assumptions regarding your datas types.
What change would you expect in the langage? making pure function automatically @safe? That may not be such a ba idea. However, that is not even enough, you could still create bug from optimizations with casting outside the pure function (for instance, you could alias variables that should not be aliased).
The only possibility to completely avoid this kind of bug is to forbid either optimization or casting. That's not going to happen in D.
|
July 04, 2012 Re: Pure functions and pointers (yes, again) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christophe Travert | On Wednesday, July 04, 2012 09:21:35 Christophe Travert wrote:
> What change would you expect in the langage? making pure function automatically @safe? That may not be such a ba idea. However, that is not even enough, you could still create bug from optimizations with casting outside the pure function (for instance, you could alias variables that should not be aliased).
An @safe function is only as safe as the @trusted functions that it calls. With @trusted, it's up to the programmer to determine that the @system stuff being done is actually being done in a way which is ultimately @safe (e.g. not using undefined behavior). If the programmer screwed up, and the @trusted stuff has buffer overruns or whatnot, then the @safe code isn't really @safe. With both @trusted and casts, it's up to the programmer to get them right, because what the programmer is doing is telling the compiler that they know better than the compiler and that they know what they're doing. If they do know better, then great. But if they don't, say hello to some nasty bugs.
_All_ of the guarantees that the compiler gives are based on the type system. So, anything that the programmer does to work around the type system must be verified and guaranteed by the programmer to ultimately maintain the guarantees that compiler expects. Otherwise, the compiler's guarantees are based on wrong assumptions, and they're going to be invalid.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation