On Wed, 23 Feb 2011 13:13:35 -0500, bearophile <bearophileh...@lycos.com> wrote:

Steven Schveighoffer:

cast voids all warranties ;)

OK. But that idea is unchanged if you remove the cast and return an int* from that function.

That is allowed, and it's expected that a pure function can return different references with identical calls.

Even if the return value is an immutable reference, it is allowed to return different references with identical calls. You should never expect that a pure optimization occurs. All you should expect is that a pure function returns the same value for identical calls. Same value does not mean the same bits.

Allowing malloc is somewhat exceptional because you then must allow free. But I see no reason (yet) to disallow free. If free cannot be pure, then
malloc cannot be pure.

I suggest to disallow both malloc/calloc and free inside pure functions, because what malloc returns a pointer, that is a value, that is not deterministic, it changes across different calls to malloc.

pure functions are not necessarily @safe functions, you can access pointers.

A weakly pure function
allows one to modularize pure functions, whereas prior to this, things
like sort could not be pure functions, and therefore could not be used
inside pure functions.  I think the hole allows pure functions to be
actually usable and easy whereas before they were much too obscure to be
useful in much code.

I think this is unrelated to the hole I was talking about.

Then I don't know of the hole you mean. Pure functions are 100% about optimization. An optimization should *never* be assumed. That is, given a pure function foo that returns a string, it should not be assumed that:

auto s = foo();
auto s2 = foo();

is always factored into

auto s = foo();
auto s2 = s;

It's an optimization, one which the compiler could or could not decide to use.

However, it *should* be assumed that:

assert(s == s2);

That is, the values are the same.

If you are going to use casts, then those rules are out the window.

All that is required is to disallow casting.

Disallowing casting is not enough here.

What are your expectations for pure functions?

I have written two more posts after that, but you may have missed them because I have broken the tread:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=130426

Some examples:

class Foo {
  int x;
  bool opEquals(Foo o) { return x == o.x; }
}
pure Foo bar() {
  return new Foo; // OK
}
void main() {
  Foo f1 = bar(); // OK
  Foo f2 = new Foo;
  f1.x = 10; // OK
  assert(f1 != f2); // OK
  f1 = f2; // OK
  assert(f1 is f2); // no
}

Here bar() allocated memory and it's pure, this is OK. f1 is mutable. You are allowed to call opEquals. You are allowed to overwrite the reference f1. But you aren't allowed to read the reference f1, because this breaks the referential transparency of the results of pure functions.

There is no such guarantee for weakly-pure functions. There's not even such a guarantee for strong-pure functions. To guarantee this would require some sort of memoization, and require optimizations to be followed.

The idea is a subtype of pointers/references, that at compile-time doesn't allow to read the value of the pointer/reference itself. I think this is able to patch the hole I was talking about (a cast is able to punch a hole again in this, of course).

I don't see any value in disallowing such accesses. The expectation that two pure function calls will necessarily return the *exact* same bits when the function is returning references/pointers is incorrect.

-Steve

Reply via email to