On Mon, 14 Apr 2014 06:37:18 -0400, Jonathan M Davis <jmdavisp...@gmx.com> wrote:

On Sunday, April 13, 2014 01:52:13 bearophile wrote:
Jonathan M Davis:
> Honestly, I would have considered that to be a bug. Converting
> the return type
> to a different level of mutability based on purity is one
> thing. Automatically
> casting the return value just because the function is pure is
> another matter
> entirely. Clearly, it can work, but it seems incredibly sloppy
> to me.

In foo1 D is working as designed, as this was a desired feature,
it has passed the Kenji and Walter review, and it was implemented
several months ago. It's a very handy way to create immutable
data with pure functions and it's safe, it's safer than
assumeUnique that is just a convention. Very recently Walter has
further improved this feature, allowing more implicit conversion
cases. So it's the opposite of a bug, it saves you from bugs in
three different ways.

Well, it's the first I've heard of it, and I certainly don't like the idea,
but if it's intended and implemented, then that's the way it is, I guess.
Maybe I'll come to agree after thinking about it more.

Here is how I consider it...

The foo1 function for reference:

string foo1(in string s) pure nothrow {
     auto s2 = s.dup;
     s2[0] = 'a';
     return s2; // OK.
}

The compiler accepts only immutable references. Any mutable references inside a pure function that only accepts immutable references can ONLY be data that is uniquely referenced from this function. In other words, there's no possible way that data is referenced outside this function, because a pure function cannot access globals.

So it's logical to assume that any mutable data inside the function can be implicitly cast to immutable. In fact, I would say in general, mutable data can be cast to immutable inside any pure function that only accepts immutable parameters. However, it cannot use the mutable references after casting. This would confuse the optimizer, which thinks that immutable data is still immutable.

For that reason, I would disallow out parameters from casting implicitly.

e.g.:

pure string mkcopy(string s) pure nothrow { return s.idup; }

void foo2(in string s, ref string r, ref string r2) pure nothrow {
    auto s2 = s.dup;
    r2 = s2;
    auto s3 = mkcopy(r2); // should be a pure copy of s
    s2[0] = 'a'; // modified immutable data referenced by r2!
    r = mkcopy(r2); // ???
}

At the line marked ???, note that the compiler has already called mkcopy on r2, which hasn't itself changed, and data r2 references is immutable. The compiler is fully allowed to change that line to:

r = s3;

which would mean that r != r2, even though the last line says otherwise.

I think the point of restricting to the return value is not only that you are sure nothing else can refer to the data, but also that nothing else happens to the mutable copy after the cast.

I wonder if scope(exit) usage could compromise the current rule...

-Steve

Reply via email to