Prototype of Ownership/Borrowing System for D

mipri mipri at
Wed Nov 20 20:50:26 UTC 2019

On Wednesday, 20 November 2019 at 19:14:52 UTC, Jab wrote:
> I don't see why this can't just be attached to @safe, if this 
> is a feature to prevent memory corruption. That's exactly what 
> @safe is for.

Well, @live enables a static check, with no runtime cost, but
adding @safe to code also makes it retain bounds checks by 
@live you might want to just place everywhere you can, at a cost
only to programmer time, but if you add @safe everywhere you might
then want to remove bounds checks also from @safe code, which 
removes the potentially useful distinction.

Anyway, the comment from the pull request is "This is far enough
along that it can be experimented with."

For example, if you think @live should be folded into @safe, you
can write some code while always trying to put @safe alongside
@live, and maybe you'll end up with some results like:

a. I was always able to easily do this, but now I have all these
"@safe @live" in my code and frankly any function with only one of
these attributes is only going to lack the other attribute due to
an oversight, so why not merge these attributes?

b. I found I couldn't add @live to lots of @safe functions for
whatever reason. If these attributes were merged I would have to
downgrade these functions to @trusted, and in practice I'd lose a
ton of safety provisions, just because my code is incompatible 
borrow checking.

c. I found that trying to add @safe to @live functions resulted in
my breaking portions of the @live functions code out into new
@trusted @live functions. If @live was merged with @safe I'd just
lose borrow checking of these functions.

An example of the third case follows, where factory() and then
newPerson() are results of wanting to add @safe.

import std;
import core.stdc.stdlib: malloc;

struct Person {
     uint age;
     uint karma;
     char[0] _name; // a C-style "flexible array member"

     static Person* factory(size_t size) @live @safe
     in { assert(size >= 4); }
     body {
         Person* newPerson() @live @trusted {
             auto partial = cast(Person*)malloc(Person.sizeof + 
             partial._name.ptr[0] = '\0';
             return partial;
         auto p = newPerson();
         p.age = uint.init;
         p.karma = uint.init;
         return p;

     // Conditional jump or move depends on uninitialised value(s)
     void identify() @live @trusted {
         _name.ptr[0..4] = "Bob\0";

     string name() @live @trusted {
         return _name.ptr.fromStringz.idup;

void birthday(scope Person* p) @live @safe {

void consume(Person* p) @safe { }

void main() @safe @live {
     auto p = Person.factory(4);
     writeln(, " ", p.age);

More information about the Digitalmars-d mailing list