Search code examples
nullrustidioms

Should we use Option or ptr::null to represent a null pointer in Rust?


The standard library's linked-list Node uses the Option type:

struct Node<T> {
    next: Option<NonNull<Node<T>>>,
    prev: Option<NonNull<Node<T>>>,
    element: T,
}

and creates a node with this code:

Node {
    next: None,
    prev: None,
    element,
}

The implementation of LeafNode of BTree, the standard library uses a raw pointer for the parent node:

struct LeafNode<K, V> {
    parent: *const InternalNode<K, V>,
    parent_idx: MaybeUninit<u16>,
    len: u16,
    keys: MaybeUninit<[K; CAPACITY]>,
    vals: MaybeUninit<[V; CAPACITY]>,
}

and creates new leaf nodes by setting parent to ptr::null:

LeafNode {
    keys: MaybeUninit::uninitialized(),
    vals: MaybeUninit::uninitialized(),
    parent: ptr::null(),
    parent_idx: MaybeUninit::uninitialized(),
    len: 0
}

We can use nullptr to implement the above code in C++, so what's the difference between Option and std::ptr::null() to represent a null pointer? What's the recommended way to represent a null pointer?


Solution

  • In general, I'd recommend using NonNull<T> over *const T or *mut T, using Option as appropriate to identify when the pointer may be null.

    The reason is two-fold:

    1. Whether null is a valid value, or not, is documented and enforced when using NonNull.
    2. *const T and *mut T are essentially interchangeable, and indeed can be cast to one another, so that const or mut may provide a false sense of safety.

    The implementation of BTree may simply not have been ported over to NonNull, which is relatively recent -- it was stabilized only in 1.25.