On 02/08/12 18:24, Timon Gehr wrote:
> I think we'd indeed need ownership / an 'unique' type qualifier. This could 
> also be helpful:
> http://d.puremagic.com/issues/show_bug.cgi?id=7316
> 
> I think type system controlled aliasing is very important to make it work, so 
> another important step would be to enforce the 'scope' storage class through 
> flow-analysis.
> 
> As far as the 'unique' type qualifier goes, we need to find a suitable design:
> 
> 
> void main(){
>     auto x = new C; // if constructor is pure or scope, x can be unique
>     pragma(msg, typeof(x)); // ?
>     auto y = x; // ?
>     pragma(msg, typeof(x)," ",typeof(y)); // ?
>     x.foo(); // ?
>     spawn(&bar, x) // ?
> }
> 
> So maybe it should look more like this:
> 
> void main(){
>     auto x = new C; // pure/scope constructor
>     static assert(typeof(x) == C);
>     auto y = x;
>     y.foo(); // foo is pure or scope
>     spawn(&bar, unique x); // fine
> }
> 
> This would add unique as an unary operator to perform a safe conversion to 
> unique. Similar operators could be added for immutable/shared/const/inout. 
> Such an approach would be backwards-compatible.

"cast(uniq)x" would be much more intuitive. But, for the code above, what 
advantage would
an explicit conversion have, given that the compiler has to perform the checks 
anyway?
If spawn() has an overload that does not require conversion (and eg copies the 
object
internally) it's important that the right thing happens automatically.

> This solution uses flow-analysis to make sure that no alias to x is alive 
> after the safe conversion to unique.
> Because of the guarantees that unshared gives, the flow analysis can even 
> include unshared fields.
> 
> We could even do:
> 
> void spawn(F,T...)(F fun, T args) if(!mayHaveMutableNonUniqueAliasing!T) { 
> ... }
> void spawn(F,T...)(F fun, unique T args) 
> if(mayHaveMutableNonUniqueAliasing!T) { spawn(fun, args); }
> 
> Then the example would look like:
> 
> void main(){
>     auto x = new C; // pure or scope
>     auto y = x;
>     y.foo(); // pure or scope
>     spawn(&bar, x); // fine!
> }
> 
> x converts to unique if flow analysis can prove no alias to it is alive after 
> the conversion. The first spawn overload does not match, therefore the second 
> one is chosen. x is implicitly converted to unique and then the other 
> overload is used to finish up.
> 
> 
> Open issue:
> 
> void main(){
>     unique x = new C;
>     pragma(msg, typeof(x.z)); // ???
>     auto y = x.z; // error?
>     immutable z = x;
> }
> 
> x.z is not necessarily unique, but assigning it to y breaks the guarantees of 
> the unique qualifier of x.

This is why treating "unique" as a static storage class doesn't really work. One
of the two last lines above would have to be disallowed, and that reduces its
usefulness dramatically. The "auto" assignment either has to be illegal, or
trigger a mutation, eg to immutable. I don't think having the compiler keep
track of all possible relations would be a practical solution, even if 
theoretically
possible.

For those not reading D.learn - unique helps in other cases too:
http://lists.puremagic.com/pipermail/digitalmars-d-learn/2012-February/029547.html

artur

Reply via email to