It is now time to introduce a different kind of type: references. The basic idea is simple: references carry an address that points to some value in memory. Using this reference, we can access or change the value the reference points to.

For example:

mut a = 3
imm ref = &mut a   // ref holds a reference to a's contents
imm val = *ref     // val is now 3
*ref = 4           // a is now set to 4

The & operator obtains a reference to the variable a, effectively pointing to the value it holds. The * (de-referencing) operator is used to obtain and then change the value pointed to by the reference.

References are very useful, as they support:

Memory Management and Safety

Cone's distinctive references are more than just "pointers". They make fine-grained control over memory convenient and safe.

Let's review briefly how the versatility of region-based memory management, powered by references, can facilitate improvements to throughput, responsiveness, and memory efficiency. Likewise, references play an important role in ensuring memory and race safety.

Region-based Memory Management

In addition to global and local (stack-based) data, it is often desirable to dynamically allocate memory from the "heap" for new data objects. When memory is allocated and initialized, an owning reference is created that points to the new data object. This reference, or copies of it, may easily be used to work with this data. When the last usable reference to an allocated object expires, the object's memory is automatically recovered. This is called automatic memory management.

Many different memory management strategies exist, such as tracing garbage collection, reference counting, single-owner, arenas, pool etc. No single strategy is perfect for all needs. Their trade-offs vary widely in terms of throughput, latency, memory use and leakage, data structure flexibility, ease-of-use, etc.

Instead of restricting a program to the limitations of only one memory management strategy, as most languages do, Cone dynamically partitions memory into regions, each with its own approach to memory allocation and collection. For every new data object, Cone allows the programmer to specify, at allocation time, which region the object belongs to, according to how well it matches the object's usage profile.

Memory and Race Safety

References are also different from raw pointers in terms of safety. Although versatile, raw pointers can be very risky to use. Incorrect use can potentially cause hard-to-detect program bugs. Although the consequences are not always serious, they could be catastrophic, especially when malicious actors take advantage of undetected pointer problems to gain access or control over other peoples' privileges or information.

By contrast, usage constraints inherent to references ensure they can only be used safely:

Reference Mechanisms

To accomplish these memory management and safety responsibilities, references are composed of four largely-independent mechanisms. These are specified (often implicitly) as part of a reference's type signature:

In addition to basic references, there are also special-purpose "fat" references which are handled somewhat differently:

What's Next?

This page introduced many reference concepts rather quickly, and perhaps overwhelmingly. Let's slow down and walk through each of them carefully with examples and helpful detail. Importantly, you do not have to know everything about references to start usefully employing them.