Uh... destructors?

Steven Schveighoffer schveiguy at yahoo.com
Wed Feb 23 10:41:04 PST 2011


On Wed, 23 Feb 2011 13:13:35 -0500, bearophile <bearophileHUGS at 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


More information about the Digitalmars-d mailing list