View mode: basic / threaded / horizontal-split · Log in · Help
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)
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)
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)
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
Top | Discussion index | About this forum | D home