Note: Much of this capability is implemented except for error handling on bad allocations.
When you allocate a new value within a region, you get back an owning reference that points to the new object. For some regions, multiple alias copies may be created which are also owning references. For safety reasons, a region's automatic memory management strategy ensures that the object's memory is freed only when when the last owning reference to the object expires. This timing ensures that an owning reference is always safe to de-reference and that an object will only be freed once.
This page describes how owning references are created and used.
Creating Owning References
Let's ask a region to allocate a new value and give us back an owning reference:
imm nbrref = +rc-imm 4
This uses the plus operator to dynamically allocate and initialize a new value, specifying:
- Region which allocates the value and manages its lifetime. In this case, the value is allocated in the rc region. Later, we will explore some of the different kinds of regions supported by Cone.
- Permission. This governs what you may do with the reference. It can be a static or lock permission. uni is assumed for an owning reference when no permission is specified.
- Initial Value. A copy of this value is stored in the newly allocated memory location. In this case, it is the integer 4.
What we get back from this allocation is an owning reference, which this example stores in the variable nbrref. The inferred type of this reference looks similar to the allocation: +rc-imm i32. This type signature includes the type of the initial value as the reference's value type.
A type's constructor or initializer may be specified as the initial value.
imm gcref = +gc-mut Point3[1f, 2f, 3f] // Allocate a new Point3 value using a constructor
Creating Multiple References to the Same Value
The creation of the first owning reference to a new value always comes from an allocation, as shown above. Additional owning references to that value may then be created by copying an existing reference via assignment or function calls:
imm nbrref = +rc-imm 4 imm nbrref2 = nbrref // nbrref2 and nbrref point to same value
How References and Allocations Expire
Owning references keep the value they point to alive. So long as a value has at least one owning reference that points to it, the value's region will not dispose of the value and reclaim its memory space. Only when all references to a value expire does the region have the right to free the value (although how quickly this happens varies by region).
So, when does the lifetime of an owning reference expire? When the data structure it is bound to expires or changes its value. If the reference is never stored anywhere, it is consumed by the expression it is part of and expires nearly immediately. If the reference is stored in a variable, it expires no later than the end of the lexical scope that variable is declared within (and sooner, obviously, if the variable takes on a new value). If the reference is pointed at by another reference, then the lifetime of the former depends on the lifetime of the latter.
When all references to an allocated value expire and the region has decided to reclaim the value's space, the region will automatically invoke the value's finalizer, if it has been defined.
Memory Allocation Errors
Although unlikely, it is still possible for memory allocation requests to fail. This typically happens when not enough contiguous, free memory exists to satisfy the request.
Failure to allocate memory will trigger a different response depending on whether the owning reference is marked as nullable.
- Non-nullable reference: the program will panic and shut down.
- Nullable reference: A failed allocation returns the value null. Any of the mechanisms provided for handling nullable values may be applied in an attempt to recover from this problem.