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