Understanding the need for smart pointers.
This article is part of a series starting with Learning Rust by Contrasting with TypeScript: Part 1 .
Let us walk through the examples in the Rust Book Smart Pointers section and contrast them with TypeScript .
A pointer is a general concept for a variable that contains an address in memory. This address refers to, or “points at,” some other data. The most common kind of pointer in Rust is a reference… Smart pointers, on the other hand, are data structures that not only act like a pointer but also have additional metadata and capabilities.
— Rust — Smart Pointers
There are a number of different smart pointers, and you a create custom ones, the Rust Book focuses on just three: Box<T>, Rc<T> , and RefCel<T> ; each solving a particular type of problem.
The most straightforward smart pointer is a box, whose type is written Box<T>. Boxes allow you to store data on the heap rather than the stack. What remains on the stack is the pointer to the heap data.
While the concept itself is straightforward, it is not until the Cons example does the usefulness of Box<T> become clear with their key feature being:
Because a Box<T> is a pointer, Rust always knows how much space a Box<T> needs: a pointer’s size doesn’t change based on the amount of data it’s pointing to.
Because of this feature, we can define a recursive data structure, List :
In TypeScript , never do you concern yourself about data being stored on the stack or the heap; we just think of everything (except maybe primitives) as references. With this in mind, we do not need any additional language feature to support a similar recursive data structure.
The following describes the core concepts:
Smart pointers are usually implemented using structs. The characteristic that distinguishes a smart pointer from an ordinary struct is that smart pointers implement the Deref and Drop traits. The Deref trait allows an instance of the smart pointer struct to behave like a reference so you can write code that works with either references or smart pointers. The Drop trait allows you to customize the code that is run when an instance of the smart pointer goes out of scope.
— Rust — Smart Pointers
Because in TypeScript , we only have one kind of reference and the garbage collector deallocates memory whenever data does not have a reference to it, the problems these traits solve are not relevant in TypeScript .
Rust has a type called Rc<T>, which is an abbreviation for reference counting. The Rc<T> type keeps track of the number of references to a value which determines whether or not a value is still in use. If there are zero references to a value, the value can be cleaned up without any references becoming invalid.
Again, the usefulness of it is not apparent until you see it solve a particular problem; in this case it is allows you to create variables b and c based on variable a in the following example.
In this case, the Rc::clone(&a) is creating a new pointer to the data on the heap; uses reference counting to avoid having to be concerned about the lifetime of a .
Thinking about TypeScript , this is essentially the same approach the garbage collector handles for you automatically; here again we do not need any additional language feature to essentially do the same thing.
Interior mutability is a design pattern in Rust that allows you to mutate data even when there are immutable references to that data; normally, this action is disallowed by the borrowing rules. To mutate data, the pattern uses unsafe code inside a data structure to bend Rust’s usual rules that govern mutation and borrowing
Unfortunately, the example in the Rust Book is a complex use case; so much so, I wrote a simplified use for RefCell<T> inspired by the following:
However, there are situations in which it would be useful for a value to mutate itself in its methods but appear immutable to other code. Code outside the value’s methods would not be able to mutate the value. Using RefCell<T> is one way to get the ability to have interior mutability.
Again in TypeScript , there is no need for such a construct as all references are mutable.