Jump to page: 1 2 3
Thread overview
DIP49 - Define qualified postblit
Nov 10, 2013
Kenji Hara
Nov 10, 2013
deadalnix
Nov 10, 2013
Kenji Hara
Nov 10, 2013
Timon Gehr
Nov 10, 2013
Kenji Hara
Nov 11, 2013
Marco Leise
Nov 12, 2013
Kenji Hara
Nov 10, 2013
Timon Gehr
Nov 10, 2013
Kenji Hara
Nov 10, 2013
Timon Gehr
Nov 10, 2013
Daniel Murphy
Nov 10, 2013
Kenji Hara
Nov 10, 2013
Daniel Murphy
Nov 12, 2013
Kenji Hara
Nov 10, 2013
Daniel Davidson
Nov 10, 2013
Kenji Hara
Nov 10, 2013
Daniel Davidson
Nov 10, 2013
Timon Gehr
Nov 12, 2013
Kenji Hara
Nov 17, 2013
Jonathan M Davis
November 10, 2013
http://wiki.dlang.org/DIP49

Experimental compiler/druntime patches (WIP, 80% completed): https://github.com/9rnsr/dmd/tree/qual_pblit https://github.com/9rnsr/druntime/tree/qual_pblit

Kenji Hara


November 10, 2013
On Sunday, 10 November 2013 at 06:46:47 UTC, Kenji Hara wrote:
> http://wiki.dlang.org/DIP49
>
> Experimental compiler/druntime patches (WIP, 80% completed):
> https://github.com/9rnsr/dmd/tree/qual_pblit
> https://github.com/9rnsr/druntime/tree/qual_pblit
>
> Kenji Hara

I like it up to the unique part. For mutable/const/immutable postblit, I do think this is it, you nailed it perfectly.

For the unique part, this become tricky, as we do not specify what is a unique expression. For this, I do not think that overloading inout make too much sense. inout already mean something else, and uniqueness is generally a useful concept that is not reserved to postblit. In fact, to make the unique posblit work, it is required that we define unique expression, and that is way beyond the scope of this DIP.

Additionally, inout posblit make sense without changing the meaning of posblit, which make the proposal confusing.

Let's make the posblit inout be what inout always has been : a wildcard for a qualifier in the callee that is known from the caller.
November 10, 2013
On 11/10/2013 07:46 AM, Kenji Hara wrote:
> http://wiki.dlang.org/DIP49
>
> Experimental compiler/druntime patches (WIP, 80% completed):
> https://github.com/9rnsr/dmd/tree/qual_pblit
> https://github.com/9rnsr/druntime/tree/qual_pblit
>
> Kenji Hara

Well written DIP!

- Rules [c1] and [c5] are unsound and should be removed.

const(int)[] constglobal;

struct S{
    int[] arr;
    this(this)const{
        arr = constglobal;
    }
}

int[] coerceC1Unsound(const(int)[] g){
    constglobal = g;
    S s;
    S t=s;
    // ... (any code that makes the above invoke postblit)
    return t.arr;
}

immutable(int)[] coerceC5Unsound(const(int)[] g){
    constglobal = g;
    S s;
    immutable(S) t=s;
    // ... (ditto)
    return t.arr;
}

- Typo in immutable postblit description: "You can regard the [i2] case
  as that the generated immutable copy is referred by const reference."
  Should read: "You can regard the [i1] case ..."

- Unique postblit:
 = The general concept seems useful, but what about this case:

struct S{
    int[] a; // should be shared between all copies
    int[] b; // should be cloned across copies

    this(this)/+same qualifier on source and target+/{
        b = b.dup;
    }
}

void main(){
    S s;
    immutable(S) t;
    auto g = s;
    auto h = t;
    // ...
}

 = Do you think that in this case one should implement identical
   mutable and immutable postblit?

 = "Pure function call which returns unique object"
   -> "Strongly pure ..."

 = "New expression with unique arguments"
   -> "Pure new expression ..."

 = (Also, the inadequacy of 'inout' becomes painfully obvious: Clearly,
   we'd want 'inout' to mean something different for the source and
   target struct instances. Then the definition of what is unique
   would not be necessary in this DIP. (Anything that converts to inout
   would be fine anyway.))

November 10, 2013
2013/11/10 deadalnix <deadalnix@gmail.com>

> I like it up to the unique part. For mutable/const/immutable postblit, I do think this is it, you nailed it perfectly.
>

Thans for the comment, @deadlnix.

For the unique part, this become tricky, as we do not specify what is a
> unique expression. For this, I do not think that overloading inout make too much sense. inout already mean something else, and uniqueness is generally a useful concept that is not reserved to postblit. In fact, to make the unique posblit work, it is required that we define unique expression, and that is way beyond the scope of this DIP.
>

The unique expression concept is not a trick. It already exists in D.

Currently sometimes you can qualify returned objects from a pure function with arbitrary qualifier.

int[] foo(int n) pure { ... }
int[] marr = foo(1);
const int[] carr = foo(1);
immutable int[] iarr = foo(1);

The reason why it's possible is that the pure function call `foo(1)` makes
unique expression.

Currently you can create arbitrary typed array object by using just only one syntax.

int[] marr = [1,2,3];
const int[] carr = [1,2,3];
immutable int[] iarr = [1,2,3];

The reason why it's possible is that the array literal makes unique expression.

So, the "unique expression" is the name for one another aspect of existing D concept.


> Additionally, inout posblit make sense without changing the meaning of posblit, which make the proposal confusing.
>
> Let's make the posblit inout be what inout always has been : a wildcard for a qualifier in the callee that is known from the caller.
>

No, the unique postblit concept is strongly related to inout type qualifier.

Condider a case that copying "inout struct" inside inout function.

struct S {
    int[] arr;
    this(this) ??? { }
}
int[] foo(inout S src)
{
    S dst = src; // copy inout S to S
    return dst.arr;
}

If the struct S has postblit, what shold be done for "copying S from inout to mutable"?

1. You cannot modify elements of arr field, because originally it may be
immutable.
2. You must re-initialize arr field by unique expression, otherwise it may
break type system

The requirements are exactly same as what necessary for unique postblit. Essentially "creating unique copy" is exactly same as "treating the copy source as inout".

Kenji Hara


November 10, 2013
2013/11/10 Timon Gehr <timon.gehr@gmx.ch>

> On 11/10/2013 07:46 AM, Kenji Hara wrote:
>
>> http://wiki.dlang.org/DIP49
>>
>> Experimental compiler/druntime patches (WIP, 80% completed): https://github.com/9rnsr/dmd/tree/qual_pblit https://github.com/9rnsr/druntime/tree/qual_pblit
>>
>> Kenji Hara
>>
>
> Well written DIP!
>

Thank you!


> - Rules [c1] and [c5] are unsound and should be removed.
>
> const(int)[] constglobal;
>
> struct S{
>     int[] arr;
>     this(this)const{
>         arr = constglobal;
>     }
> }
>
> int[] coerceC1Unsound(const(int)[] g){
>     constglobal = g;
>     S s;
>     S t=s;
>     // ... (any code that makes the above invoke postblit)
>     return t.arr;
> }
>
> immutable(int)[] coerceC5Unsound(const(int)[] g){
>     constglobal = g;
>     S s;
>     immutable(S) t=s;
>     // ... (ditto)
>     return t.arr;
> }
>

Oops... Indeed [c1] and c5] may break type system... I deleted these rules from the DIP.


> - Typo in immutable postblit description: "You can regard the [i2] case
>   as that the generated immutable copy is referred by const reference."
>   Should read: "You can regard the [i1] case ..."
>

Thanks. Fixed.

- Unique postblit:
>  = The general concept seems useful, but what about this case:
>
> struct S{
>     int[] a; // should be shared between all copies
>     int[] b; // should be cloned across copies
>
>     this(this)/+same qualifier on source and target+/{
>         b = b.dup;
>     }
> }
>
> void main(){
>     S s;
>     immutable(S) t;
>     auto g = s;
>     auto h = t;
>     // ...
> }
>
>  = Do you think that in this case one should implement identical
>    mutable and immutable postblit?
>

I think yes.


>  = "Pure function call which returns unique object"
>    -> "Strongly pure ..."
>

This is valid. Because not only strongly pure function will return unique object.

For example:
  immutable(int)[] foo(int[] iarr) pure { ... }
  int[] marr = foo([1,2,3]);
  // foo will never return the arr argument (without unsafe cast).


>  = "New expression with unique arguments"
>    -> "Pure new expression ..."
>

I'm not sure that "pure new expression" is widely used word in D...


>  = (Also, the inadequacy of 'inout' becomes painfully obvious: Clearly,
>    we'd want 'inout' to mean something different for the source and
>    target struct instances. Then the definition of what is unique
>    would not be necessary in this DIP. (Anything that converts to inout
>    would be fine anyway.))
>

As I already answered to deadalnix,  it is strongly related to inout. To describe about that, I added a section "Why use 'inout' keyword for 'unique' postblit?" in DIP.

Kenji Hara


November 10, 2013
On 11/10/2013 12:07 PM, Kenji Hara wrote:
> Condider a case that copying "inout struct" inside inout function.
>
> struct S {
>      int[] arr;
>      this(this) ??? { }
> }
> int[] foo(inout S src)
> {
>      S dst = src; // copy inout S to S
>      return dst.arr;
> }
>
> If the struct S has postblit, what shold be done for "copying S from
> inout to mutable"?
>
> 1. You cannot modify elements of arr field, because originally it may be
> immutable.
> 2. You must re-initialize arr field by unique expression, otherwise it
> may break type system
> ...

2. is not necessary in the following case:

inout(int)[] foo(inout S src){
    inout(S) dst = src; // copy inout S to inout S
    return dst.arr;
}

But as far as I understand, there is no other postblit than inout to invoke under the current proposal, hence this could be wasteful.


> The requirements are exactly same as what necessary for unique postblit.
> Essentially "creating unique copy" is exactly same as "treating the copy
> source as inout".

I think it is a good design, but maybe still incomplete.

We could eg. keep

this(this)inout{ ... }

as the unique postblit and have

this(inout this)inout{ ... }

as a postblit for identically qualified source and target.
November 10, 2013
On 11/10/2013 12:35 PM, Kenji Hara wrote:
> 2013/11/10 Timon Gehr <timon.gehr@gmx.ch <mailto:timon.gehr@gmx.ch>>
> ...
>
>       = Do you think that in this case one should implement identical
>         mutable and immutable postblit?
>
>
> I think yes.
>

This still leaves the issue outlined in the other post though. How to copy inout to inout?

>       = "Pure function call which returns unique object"
>         -> "Strongly pure ..."
>
>
> This is valid. Because not only strongly pure function will return
> unique object.
> ...

inout(int[]) identity(inout(int[]) x)pure{ return x; }

struct S{
    int[] arr;
    this(this)inout{
        arr = identity(arr); // whoops
    }
}

But you are right, strongly pure is the wrong term. It is 'pure with unique arguments'.

> For example:
>    immutable(int)[] foo(int[] iarr) pure { ... }
>    int[] marr = foo([1,2,3]);
>    // foo will never return the arr argument (without unsafe cast).
>
>       = "New expression with unique arguments"
>         -> "Pure new expression ..."
>
>
> I'm not sure that "pure new expression" is widely used word in D...

"New expression using a pure-qualified constructor with unique arguments."

>
>       = (Also, the inadequacy of 'inout' becomes painfully obvious: Clearly,
>         we'd want 'inout' to mean something different for the source and
>         target struct instances. Then the definition of what is unique
>         would not be necessary in this DIP. (Anything that converts to inout
>         would be fine anyway.))
>
>
> As I already answered to deadalnix,  it is strongly related to inout.
> To describe about that, I added a section "Why use 'inout' keyword for
> 'unique' postblit?" in DIP.
>
> Kenji Hara

Sure, this makes sense to me. What I was referring to is the following hypothetical design, that allows multiple different inout-qualifiers, for example denoted by inout/n, where n is some integral constant:


inout(int[]) identity(inout(int[]) x){
    writeln("foo"); // not pure
    return x;
}

struct S{
    int[] a;
    int[] b;
    int[] c;
    int[] d;
    this(inout/1 this)inout/2{
        static assert(is(typeof(a)==inout/1(int[])));
        a = b; // error: b of type inout/1(int[]) is not
               // implicitly convertible to inout/2(int[])
        b = somePureFunction(new int[] a);  // ok
        c = identity(new inout/2(int)[] a); // ok, even though identity
                                            // _not pure_
        // error: d has not been reassigned
    }
}





November 10, 2013
2013/11/10 Timon Gehr <timon.gehr@gmx.ch>

> On 11/10/2013 12:07 PM, Kenji Hara wrote:
>
>> Condider a case that copying "inout struct" inside inout function.
>>
>> struct S {
>>      int[] arr;
>>      this(this) ??? { }
>> }
>> int[] foo(inout S src)
>> {
>>      S dst = src; // copy inout S to S
>>      return dst.arr;
>> }
>>
>> If the struct S has postblit, what shold be done for "copying S from inout to mutable"?
>>
>> 1. You cannot modify elements of arr field, because originally it may be
>> immutable.
>> 2. You must re-initialize arr field by unique expression, otherwise it
>> may break type system
>> ...
>>
>
> 2. is not necessary in the following case:
>
> inout(int)[] foo(inout S src){
>     inout(S) dst = src; // copy inout S to inout S
>     return dst.arr;
> }
>
> But as far as I understand, there is no other postblit than inout to invoke under the current proposal, hence this could be wasteful.
>
>
>
>  The requirements are exactly same as what necessary for unique postblit.
>> Essentially "creating unique copy" is exactly same as "treating the copy source as inout".
>>
>
> I think it is a good design, but maybe still incomplete.
>
> We could eg. keep
>
> this(this)inout{ ... }
>
> as the unique postblit and have
>
> this(inout this)inout{ ... }
>
> as a postblit for identically qualified source and target.
>

Hmm.
As a side note, I'm planning unique constructor definition.

struct S {
    // If constructor has one or more inout parameters, it will become
inout constructor
    // The constructed object qualifier will be restricted by the argument
types.
    this(inout int[] arr) inout { ... }

    // If constructor has no inout parameters, it will become unique
constructor
    // The constructed object type can have arbitrary qualifier
    this(int[] arr) inout { ... }
}

So, separating "inout postblit' and 'unique postblit' may be reasonable.

(However, it seems to me that the syntax "this(inout this) inout;" looks
weird...

Kenji Hara


November 10, 2013
"Kenji Hara" <k.hara.pg@gmail.com> wrote in message news:mailman.336.1384083327.9546.digitalmars-d@puremagic.com...
>
> This is valid. Because not only strongly pure function will return unique object.
>
> For example:
>  immutable(int)[] foo(int[] iarr) pure { ... }
>  int[] marr = foo([1,2,3]);
>  // foo will never return the arr argument (without unsafe cast).
>

This one is incorrect, the value returned from foo could be an immutable global.  The unique conversion is only capable of changing non-mutable to immutable, not the other way around.

Maybe you meant something like this?

int[] foo(const(int)[] iarr) pure { ... }


November 10, 2013
On Sunday, 10 November 2013 at 06:46:47 UTC, Kenji Hara wrote:
> http://wiki.dlang.org/DIP49
>
> Experimental compiler/druntime patches (WIP, 80% completed):
> https://github.com/9rnsr/dmd/tree/qual_pblit
> https://github.com/9rnsr/druntime/tree/qual_pblit
>
> Kenji Hara

Does the analysis hold up the same if the type held in the array itself has mutable aliasing?

struct T { int[] i; }
struct S { T[] t; }

Also, does it hold up with associative arrays?

struct S { string[string] aa; }

With this design, is there no need then for struct constructors - or would this be orthogonal or in addition to those?

Thanks
Dan

« First   ‹ Prev
1 2 3