| |
 | Posted by Timon Gehr in reply to Walter Bright | Permalink Reply |
|
Timon Gehr 
Posted in reply to Walter Bright
| On 10/24/22 06:26, Walter Bright wrote:
> On 10/23/2022 6:50 PM, Timon Gehr wrote:
>> It kind of does a bit with return annotations:
>>
>> ```d
>> int* foo(return scope int* x)@safe{
>> auto y=x;
>> int t;
>> auto z=&t;
>> return y; // ok, but can't return z
>> }
>> ```
>
> It isn't actually tracking lifetimes, it just copies the attributes from x to y. z gets the scope attribute because it is initialized with the address of a stack variable.
> ...
Well, yes, this is essentially how to track lifetimes.
Right now, there are two kinds of lifetimes (attached to declaration using annotations). Some lifetimes outlive the current function and others are strictly lexical.
To get more expressiveness, you could:
- have more than one lifetime that exceeds the current function's lifetime. I.e., multiple distinct return annotations, ideally an arbitrary number, by allowing the return annotation to be parameterized by a lifetime variable.
- have such parameterized scope return annotations on fields of aggregates.
None of this requires a fundamentally different approach than what DIP1000 does. What's missing is:
- a way to parameterize functions and aggregates that is completely erased at runtime (generally useful, not only for lifetimes; e.g., this is how to fix `inout`.)
- return storage class parameterized by a lifetime variable
By default, people write their code in the current DIP1000 subset, but library authors get more expressiveness to build containers that actually work well with DIP1000.
>
>> I guess my issue here is that @live, while it may use some methods that may be helpful in another context, does not enable any of the use cases I described either. It does not make @safe any safer and it also does not make DIP1000 any more modular.
>
> @live's purpose is to prevent:
>
> 1. use after free
> 2. multiple free's
> 3. no free
> ...
Yes, as some sort of linter within @system/@trusted code. DIP1000 is for @safe code. (I don't really see why @system and @trusted code should have access to more static analysis muscle that @safe code, but it's not even strictly needed in order to make DIP1000 vastly more expressive.)
I think there is currently more demand for a type system that does not get in your way in @safe code than for a linter that helps you get malloc/free in @system/@trusted code right.
> To go further than that will require the user to construct a container that encapsulates whatever it does, and is likely going to include some @trusted functionality. Which is more or less what Rust does.
> ...
Yes, but the magic is in expressive interfaces that actually allow the implementation to be @trusted because the type checker can correctly restrict @safe code in a way that allows the @trusted code to make assumptions about the behavior of said @safe code.
Note that @live loses all guarantees at interface boundaries, but those are what actually matters for modular safety in the style of Rust. DIP1000 does not lose guarantees at interface boundaries, which means this is the more promising approach that people will want to extend.
>
>> I agree that it is quite useful for some cases. It just does not seem to offer all that much yet in terms of actually enabling safe manual memory management for the entire application.
>
> Without the 1,2,3 above, you're right that DIP1000 is not a complete solution. But it is a necessary precondition for doing 1,2,3.
>
DIP1000+@live is also not a "complete solution". One (less important) reason is because @live does not address 1,2,3 in @safe code. Another (more important) reason is that DIP1000 is not really expressive enough to create some common containers encapsulating @trusted functionality. (E.g., region allocators.)
I agree with the abstract motivation for DIP1000, it's just that I predict that the actual implementation will in practice be too restrictive to achieve the stated goals.
|