Jump to page: 1 2
Thread overview
Implicit conversions through purity
Apr 12, 2014
bearophile
Apr 13, 2014
Jonathan M Davis
Apr 13, 2014
bearophile
Apr 14, 2014
Jonathan M Davis
Apr 14, 2014
bearophile
Apr 15, 2014
Steve Teale
Apr 15, 2014
bearophile
Apr 15, 2014
Steve Teale
Apr 15, 2014
bearophile
Apr 16, 2014
Steve Teale
Apr 16, 2014
Jonathan M Davis
Apr 13, 2014
Daniel Murphy
Apr 14, 2014
Jonathan M Davis
Apr 13, 2014
Daniel Murphy
Apr 13, 2014
bearophile
April 12, 2014
Is it possible and a good idea to allow code like the function foo2?


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

void foo2(in string s, ref string sOut) pure nothrow {
    auto s2 = s.dup;
    s2[0] = 'a';
    sOut = s2; // Error: cannot implicitly convert
}

void foo3(in string s, out string sOut) pure nothrow {
    auto s2 = s.dup;
    s2[0] = 'a';
    sOut = s2; // Error: cannot implicitly convert
}

void main() {}


Bye,
bearophile
April 13, 2014
On Saturday, April 12, 2014 21:26:01 bearophile wrote:
> Is it possible and a good idea to allow code like the function foo2?
> 
> 
> string foo1(in string s) pure nothrow {
>      auto s2 = s.dup;
>      s2[0] = 'a';
>      return s2; // OK.
> }

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.

- Jonathan M Davis
April 13, 2014
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.

But my question was about the successive foo functions :-)

Bye,
bearophile
April 13, 2014
"Jonathan M Davis"  wrote in message news:mailman.112.1397351369.5999.digitalmars-d-learn@puremagic.com...

> 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.

It's not a bug, and it's not another matter entirely - it's the same thing as converting a call expression, just on the inside instead of the outside. 

April 13, 2014
"bearophile"  wrote in message news:hxdrbyqrhwvuochlhclc@forum.dlang.org... 

> Is it possible and a good idea to allow code like the function foo2?

It seems reasonable.
April 13, 2014
Daniel Murphy:

> It seems reasonable.

OK, added:
https://issues.dlang.org/show_bug.cgi?id=12573

Bye,
bearophile
April 14, 2014
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.

> But my question was about the successive foo functions :-)

Well, if I don't like the first example, I'm not about to be in favor of making more examples follow suite.

- Jonathan M Davis
April 14, 2014
On Sunday, April 13, 2014 21:21:02 Daniel Murphy wrote:
> "Jonathan M Davis"  wrote in message news:mailman.112.1397351369.5999.digitalmars-d-learn@puremagic.com...
> 
> > 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.
> 
> It's not a bug, and it's not another matter entirely - it's the same thing as converting a call expression, just on the inside instead of the outside.

Doing the conversion on the caller's side enables code that wouldn't otherwise work - particularly if you're not intimately familiar with what guarantees pure really gives you. Doing the conversion inside the function doesn't really buy you much of anything IMHO and promotes being lazy with types. It may not be a big deal, but I don't think that it's really a good idea either.

So, while from the perspective of what the compiler can guarantee, it may be the same from both sides, I don't think that it's the same at all with regards to how it affects the programmer or what code they need to write (or should write).

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

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

If you think the proposal is not good, can you please copy what you have written here in the issue thread?
https://issues.dlang.org/show_bug.cgi?id=12573

Bye,
bearophile
« First   ‹ Prev
1 2