Implicit conversions through purity

Steven Schveighoffer schveiguy at yahoo.com
Mon Apr 14 07:44:46 PDT 2014


On Mon, 14 Apr 2014 06:37:18 -0400, Jonathan M Davis <jmdavisProg at 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


More information about the Digitalmars-d-learn mailing list