$(DDOC $(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
$(SPEC_S Live Functions,
$(DDOC_BLANKLINE )
$(HEADERNAV_TOC $(HEADERNAV_ITEM ownership, Ownership)
$(HEADERNAV_ITEM ob, Borrowing)
$(HEADERNAV_SUBITEMS live, @live
attribute,
$(HEADERNAV_ITEM tracked, Tracked Pointers)
$(HEADERNAV_ITEM state, Pointer States)
$(HEADERNAV_ITEM lifetime, Lifetimes)
$(HEADERNAV_ITEM transition, Pointer State Transitions)
$(HEADERNAV_ITEM borrower, Borrowers can be Owners)
$(HEADERNAV_ITEM exception, Exceptions)
$(HEADERNAV_ITEM lazy, Lazy Parameters)
$(HEADERNAV_ITEM mempool, Mixing Memory Pools)
$(HEADERNAV_ITEM vargs, Variadic Function Arguments)
)
$(HEADERNAV_ITEM references, References)
)
$(DDOC_BLANKLINE )
$(B Experimental, Subject to Change, use -preview=dip1021
to activate)
$(DDOC_BLANKLINE )
@live
attribute enable diagnosing these sorts of errors by
tracking the status of owner pointers.
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
const
or immutable
) data, i.e. none of them can modify the memory
object(s) pointed to.
)
$(DDOC_BLANKLINE )
$(P This is collectively called an $(I Ownership/Borrowing) system. It can be stated as:
)
$(DDOC_BLANKLINE )
At any point in the program, for each memory object, there is exactly one live mutable pointer to it or all the live pointers to it are read-only.$(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )
@live
attribute)@live
attribute are checked for compliance with
the Ownership/Borrowing rules. The checks are run after other semantic processing is complete.
The checking does not influence code generation.
)
$(DDOC_BLANKLINE )
$(P Whether a pointer is allocated memory using the GC or some other
storage allocator is immaterial to OB, they are not distinguished and are
handled identically.
)
$(DDOC_BLANKLINE )
$(P Class references are assumed to be allocated using either the GC or are allocated
on the stack as scope
classes, and are not tracked.
)
$(DDOC_BLANKLINE )
$(P If @live
functions
call non-@live
functions, those called functions are expected to present
an @live
compatible interface, although it is not checked.
if non-@live
functions call @live
functions, arguments passed are
expected to follow @live
conventions.
)
$(DDOC_BLANKLINE )
$(P It will not detect attempts to dereference null
pointers or possibly
null
pointers. This is unworkable because there is no current method
of annotating a type as a non-null
pointer.
)
$(DDOC_BLANKLINE )
@live
function
as this
, function parameters or local variables. Variables from other
functions are not tracked, even @live
ones, as the analysis of interactions
with other functions depends
entirely on that function signature, not its internals.
Parameters that are const
are not tracked.
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
scope
attribute.
If a pointer with the scope
attribute is initialized
with an expression not derived from a tracked pointer, it is an Owner.
$(DDOC_BLANKLINE )
If an Owner pointer is assigned to another Owner pointer, the
former enters the Undefined state.
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD void) consume($(D_KEYWORD int)* o); $(D_COMMENT // o is owner
)
@live $(D_KEYWORD int)* f($(D_KEYWORD int)* p) $(D_COMMENT // p is owner
){
writeln(*p);
$(D_COMMENT // transfer ownership to `consume`
) consume(p);
$(D_COMMENT // p is now undefined
) $(D_COMMENT //writeln$(LPAREN)*p$(RPAREN ); // error
)
$(D_KEYWORD int)* q = $(D_KEYWORD new) $(D_KEYWORD int); $(D_COMMENT // q is owner
) writeln(*q);
p = q; $(D_COMMENT // transfer ownership
) $(D_COMMENT // q is now undefined
) $(D_COMMENT //writeln$(LPAREN)*q$(RPAREN ); // error
) writeln(*p);
$(D_KEYWORD return) p;
}
)
)
$(DDOC_BLANKLINE )
$(DT Borrowed)
$(DDOC_BLANKLINE )
$(DD A Borrowed pointer is one that temporarily becomes the sole live pointer
to a memory object graph. It enters that state via assignment
from an owner pointer or another borrowed pointer, and stays in that state
until its last use.
$(DDOC_BLANKLINE )
A Borrowed pointer must be scope
and must
be a pointer to mutable.
A mutable scope
pointer function parameter is a Borrowed pointer.
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD void) consume($(D_KEYWORD int)* o); $(D_COMMENT // o is owner
)$(D_KEYWORD void) borrow($(D_KEYWORD scope) $(D_KEYWORD int)* b); $(D_COMMENT // b is borrowed
)
@live $(D_KEYWORD void) g($(D_KEYWORD scope) $(D_KEYWORD int)* p) $(D_COMMENT // p is borrowed
){
$(D_COMMENT //consume$(LPAREN)p$(RPAREN ); // error, p is not owner
) borrow(p);
$(D_COMMENT // lend p to q
) $(D_KEYWORD int)* q = p; $(D_COMMENT // q is inferred as scope
) $(D_COMMENT // <-- using p here would end q's lifetime
) writeln(*q);
$(D_COMMENT // lifetime of q ends before p is used
) writeln(*p); $(D_COMMENT // OK
)}
)
)
$(DDOC_BLANKLINE )
$(DT Readonly)
$(DDOC_BLANKLINE )
$(DD A Readonly pointer acquires its value from an Owner or Borrowed pointer.
While the Readonly pointer is live, only Readonly pointers can
be acquired from that Owner.
A Readonly pointer must be scope
and also
must not be a pointer to mutable.
$(DDOC_BLANKLINE )
$(D_CODE @live $(D_KEYWORD void) h($(D_KEYWORD scope) $(D_KEYWORD int)* p)
{
$(D_COMMENT // acquire 2 read only pointers
) $(D_KEYWORD const) q = p;
$(D_KEYWORD const) r = q;
$(D_COMMENT // <-- borrowing or using p here would end q and r's lifetime
)
$(D_COMMENT // both q and r are live
) writeln(*q);
writeln(*r);
$(D_COMMENT // using p ends all its read only pointer lifetimes
) writeln(*p);
$(D_COMMENT //writeln$(LPAREN)*q$(RPAREN ); // error
)}
)
)
)
$(DDOC_BLANKLINE )
out
function parameter (changes state after the function returns),
treated the same as initialization)
$(DDOC_BLANKLINE )
$(LI passed by ref
to a function parameter, treated as an assignment to a Borrow or a Readonly
depending on the storage class and type of the parameter)
$(DDOC_BLANKLINE )
$(LI returned from a function)
$(DDOC_BLANKLINE )
$(LI it is passed by value to a function parameter, which is
treated as an assignment to that parameter.)
$(DDOC_BLANKLINE )
$(LI it is implicitly passed by ref as a closure variable to a nested function)
$(DDOC_BLANKLINE )
$(LI the address of the pointer is taken, which is treated as assignment to whoever
receives the address)
$(DDOC_BLANKLINE )
$(LI the address of any part of the memory object graph is taken, which is
treated as assignment to whoever receives that address)
$(DDOC_BLANKLINE )
$(LI a pointer value is read from any part of the memory object graph,
which is treated as assignment to whoever receives that pointer)
$(DDOC_BLANKLINE )
$(LI merging of control flow reconciles the state of each variable based on the
states they have from each edge)
)
$(DDOC_BLANKLINE )
scope(exit)
:
)
$(DDOC_BLANKLINE )
$(D_CODE @live $(D_KEYWORD void) waterTight()
{
$(D_KEYWORD auto) p = malloc();
$(D_KEYWORD scope)(exit) free(p);
pitcher();
}
)
$(DDOC_BLANKLINE )
$(P or use RAII objects or call only nothrow
functions.
)
$(DDOC_BLANKLINE )
void*
in @live
functions.
)
$(DDOC_BLANKLINE )
printf
) are considered to be consumed.
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )