May 02, 2014
On Friday, 2 May 2014 at 09:41:48 UTC, Marc Schütz wrote:
> To make this more useful, turn it into a requirement. It gets us deterministic destruction for reference types. Example:
>
>         ...
>         isolated tmp = new Tempfile();
>         // use tmp
>         ...
>         // tmp is guaranteed to get cleaned up
>     }
>

No because...

> This needs more elaboration. The problem is control flow:
>
>     isolated a = new A();
>     if(...) {
>         immutable b = a;
>         ...
>     }
>     a.foo(); // <-- ???
>
> (Similar for loops and gotos.)
>
> There are several possibilities:
>

Of this.

> 1) isolateds must be consumed either in every branch or in no branch, and this is statically enforced by the compiler.
>
> 2) It's just "forbidden", but the compiler doesn't guarantee it except where it can.
>
> 3) The compiler inserts a hidden variable to track the status of the isolated, and asserts if it is used while it's in an invalid state. This can be elided if it can be proven to be unnecessary.
>

These solutions are all unnecessary restrictive. If the variable may be consumed it is consumed. This is a problem solved for ages for non nullables, there is no need to brainstorm here.

> I would prefer 3), as it is the most flexible. I also believe a similar runtime check is done in other situations (to guard against return of locals in @safe code, IIRC).
>

3 is idiotic as the compiler can't ensure anything at compile time. Random failure at runtime for valid code is not desirable.
May 02, 2014
On Friday, 2 May 2014 at 09:41:48 UTC, Marc Schütz wrote:
> That's true, but it is also a breaking change, because then suddenly some variables aren't writable anymore (or alternatively, the compiler would have to analyse all future uses of the variable first to see whether it can be inferred isolated, if that's even possible in the general case). I believe it's fine if explicit annotation is required.

No, I expect the compiler to backtrack inference when it hits an error, not to infer eagerly, because indeed, the eager inference would be a breaking change.
May 02, 2014
Correct me if I'm wrong here, but this seems really similar to how Rust does owned pointers and move semantics. Or is there a large conceptual difference between the two that I'm missing?

I believe that the issues that people are bringing up with bad interaction with UFCS, and losing isolated data after passing it to a function, are managed in Rust with the notion of a borrowed pointers. Perhaps something analogous to this could accompany the `isolated` idea?
May 02, 2014
On Friday, 2 May 2014 at 17:46:54 UTC, deadalnix wrote:
> On Friday, 2 May 2014 at 09:41:48 UTC, Marc Schütz wrote:
>> To make this more useful, turn it into a requirement. It gets us deterministic destruction for reference types. Example:
>>
>>        ...
>>        isolated tmp = new Tempfile();
>>        // use tmp
>>        ...
>>        // tmp is guaranteed to get cleaned up
>>    }
>>
>
> No because...
>
>> This needs more elaboration. The problem is control flow:
>>
>>    isolated a = new A();
>>    if(...) {
>>        immutable b = a;
>>        ...
>>    }
>>    a.foo(); // <-- ???
>>
>> (Similar for loops and gotos.)
>>
>> There are several possibilities:
>>
>
> Of this.
>
>> 1) isolateds must be consumed either in every branch or in no branch, and this is statically enforced by the compiler.
>>
>> 2) It's just "forbidden", but the compiler doesn't guarantee it except where it can.
>>
>> 3) The compiler inserts a hidden variable to track the status of the isolated, and asserts if it is used while it's in an invalid state. This can be elided if it can be proven to be unnecessary.
>>
>
> These solutions are all unnecessary restrictive. If the variable may be consumed it is consumed. This is a problem solved for ages for non nullables, there is no need to brainstorm here.

I think the situation is different here. For nullables, you wouldn't gain much by more precise tracking. For isolated, as noted, we'd gain deterministic lifetimes for reference types.
This is IMO important enough to accept a few minor complications (which are anyway solvable). There would be no more need for the unsafe std.typecons.scoped, which only works for classes anyway, but not slices or pointers.

>
>> I would prefer 3), as it is the most flexible. I also believe a similar runtime check is done in other situations (to guard against return of locals in @safe code, IIRC).
>>
>
> 3 is idiotic as the compiler can't ensure anything at compile time.

You can in most cases. Runtime failure is only for the cases where it's not possible.

> Random failure at runtime for valid code is not desirable.

It's not random, and the code was _not_ valid: it tried to use a consumed isolated.
May 02, 2014
On Friday, 2 May 2014 at 18:32:13 UTC, Dylan Knutson wrote:
> Correct me if I'm wrong here, but this seems really similar to how Rust does owned pointers and move semantics. Or is there a large conceptual difference between the two that I'm missing?
>
> I believe that the issues that people are bringing up with bad interaction with UFCS, and losing isolated data after passing it to a function, are managed in Rust with the notion of a borrowed pointers. Perhaps something analogous to this could accompany the `isolated` idea?

I don't think bolting Rust's type system onto D is a viable option at this point.
May 02, 2014
On Friday, 2 May 2014 at 18:32:13 UTC, Dylan Knutson wrote:
> Correct me if I'm wrong here, but this seems really similar to how Rust does owned pointers and move semantics. Or is there a large conceptual difference between the two that I'm missing?
>

Yes, there are some parallels, although there's no "merging of islands" in Rust, AFAIK.

> I believe that the issues that people are bringing up with bad interaction with UFCS, and losing isolated data after passing it to a function, are managed in Rust with the notion of a borrowed pointers. Perhaps something analogous to this could accompany the `isolated` idea?

This will definitely need more thought. I also don't think that UFCS is special; methods should probably be just treated like free functions with a hidden parameter, just as they are for pure.

Purity might be one part of the solution here: pure functions can for example take isolated arguments without consuming them, iff their parameters and the isolated variable have "incompatible" types in that it mustn't be possible to store a reference to one in the other. (The same is true for scoped variables: they cannot escape their scope, even if the pure function's params are not marked as scope.)

Another option are scope/in parameters.

All of this purity, isolated, scope, uniqueness business is closely intertwined... there just needs to be an elegant way to make it all fit together.
May 02, 2014
On Friday, 2 May 2014 at 18:10:42 UTC, deadalnix wrote:
> On Friday, 2 May 2014 at 09:41:48 UTC, Marc Schütz wrote:
>> That's true, but it is also a breaking change, because then suddenly some variables aren't writable anymore (or

s/writable/readable/ of course

>> alternatively, the compiler would have to analyse all future uses of the variable first to see whether it can be inferred isolated, if that's even possible in the general case). I believe it's fine if explicit annotation is required.
>
> No, I expect the compiler to backtrack inference when it hits an error, not to infer eagerly, because indeed, the eager inference would be a breaking change.

This might work, but would require defining an order of evaluation for static if's &co, because you could create logical cycles otherwise.
May 02, 2014
On Friday, 2 May 2014 at 18:32:13 UTC, Dylan Knutson wrote:
> Correct me if I'm wrong here, but this seems really similar to how Rust does owned pointers and move semantics. Or is there a large conceptual difference between the two that I'm missing?
>

There is some similarity, but Rust system has a bit more capabilities. These extra capability come at great increase in complexity, so I don't think it is worth it.

> I believe that the issues that people are bringing up with bad interaction with UFCS, and losing isolated data after passing it to a function, are managed in Rust with the notion of a borrowed pointers. Perhaps something analogous to this could accompany the `isolated` idea?

Yes, rust handle this with burrowed pointers. You can also handle this by :
 - Passing data back and forth (via argument, and then return it so the callee get it back).
 - Using a wrapper of some kind.

I don't think getting all the menagerie of Rust pointer types is a good thing. They certainly allows for a lot, but once again, come at great complexity cost. If most of it can be achieved with much lower complexity, that is a win.
May 02, 2014
On Friday, 2 May 2014 at 20:10:04 UTC, Marc Schütz wrote:
> On Friday, 2 May 2014 at 18:10:42 UTC, deadalnix wrote:
>> On Friday, 2 May 2014 at 09:41:48 UTC, Marc Schütz wrote:
>>> That's true, but it is also a breaking change, because then suddenly some variables aren't writable anymore (or
>
> s/writable/readable/ of course
>

Yes.

>>> alternatively, the compiler would have to analyse all future uses of the variable first to see whether it can be inferred isolated, if that's even possible in the general case). I believe it's fine if explicit annotation is required.
>>
>> No, I expect the compiler to backtrack inference when it hits an error, not to infer eagerly, because indeed, the eager inference would be a breaking change.
>
> This might work, but would require defining an order of evaluation for static if's &co, because you could create logical cycles otherwise.

Yes, but this is unrelated to isolated. In fact this is already the case. static if is not deterministic. I've made a proposal to improve the situation:

http://wiki.dlang.org/DIP31

But to be fair I'm not quite satisfied. This still leave some room for unspecified results, but is a great improvement over current situation.
1 2
Next ›   Last »