On Borrow Checking

jmh530 john.michael.hall at gmail.com
Wed May 7 14:47:49 UTC 2025


On Tuesday, 6 May 2025 at 20:12:18 UTC, Dukc wrote:
> On Tuesday, 6 May 2025 at 14:48:27 UTC, jmh530 wrote:
>>
>> It might be helpful to example where Rust's version of some 
>> code let's you prove something is safe with the borrow 
>> checker, but D's version doesn't.
>
> You're right. Have a look at my post earlier on this thread:
>> On Tuesday, 29 April 2025 at 17:12:41 UTC, Walter Bright wrote:
>>> So I implemented a borrow checker for D, and it is enabled by 
>>> adding the `@live` annotation for a function, which turns on 
>>> the borrow checker for that function. There are no syntax or 
>>> semantic changes to the language, other than laying on a 
>>> borrow checker.
>>
>> There's a difference.
>>
>> In Rust, as I understand it, if you have a function like
>>
>> ```Rust
>> fn free(ptr: MyCustomPointer)
>> {   // ...
>> }
>> ```
>>
>> it is 100% safe to use. The compiler will not let you 
>> double-free or use after free, unless you use the `unsafe` 
>> block to do so.
>>
>> But you can't have
>>
>> ```D
>> @trusted void free(MyCustomPointer ptr)
>> {   // ...
>> }
>> ```
>>
>> in D because it would be unsafe to use from a non-`@live` 
>> function.
>>
>> If we had a way to say that "this function can be called from 
>> `@safe`, if and only if it's usage is guarded with `@live`" 
>> then it would be equal to the Rust borrow checker.

Ah, I remember that. Thanks.

Just to be clear, the @trusted function you provide could be 
called by an @safe function, but your point is that it may 
actually be unsafe to do so. The real goal is to enable more code 
to actually be safe, not to just slap @trusted on things.

The examples in the @live spec don't reference @safe. But it does 
have an example of a non- at live release function that is called by 
an @live test function that prevents use after free.

I can think of a few different ways forward (by no means limited 
to just this)

1) Do @safe inference on @live functions. I assume a body is 
needed on @live functions (Rust requires a body unless a trait or 
extern function, and extern is only allowed in unsafe code). So 
that might be good idea on its own merits.

That being said, it doesn't really help you if the @live function 
is calling an @system function. Also, @live functions can call 
non- at live functions (although for an @safe @live function all the 
functions called by it need to be @safe/@trusted too), so it 
wouldn't necessarily be a transitive inference all the way down 
(i.e. it hits the first unattributed function and becomes 
@system).

2) Enhance the @safe definition so that an @safe @live function 
can call an @system function so long as the function it calls 
abides by certain restrictions. Obviously, the spec would need to 
clearly state what the restrictions are. One limitation would be 
that to verify that a @system function abides by these 
restrictions would require having the function body.

3) Add a @safeiflive attribute such that the function is @safe if 
called by a @live function and @system otherwise. As above, the 
team would need to pin down exactly what is allowed. After all, 
why couldn't it just be marked @safe? What @safe restrictions 
could be relaxed if @live is being enforced. Would require some 
thought, I imagine, but probably useful to think about. The 
downside is that it's more attributes.

4) Add @trustediflive, similar to above such that it is @trusted 
if called by a @live function and @system otherwise. Let's the 
user make the decision, more flexible. I think @trustediflive is 
kind of in line with what you were suggesting.


More information about the Digitalmars-d mailing list