How Rust spoils pattern matching
Tags: rust, ocaml, programming
Published: 2024-01-12 22:42:04

Rust is renowned as a great low-level language with a strong focus on safety. However, when exploring its pattern matching capabilities, especially with the `Box` type for heap allocation, certain limitations become evident.

**Understanding Rust's `Box` Type:**
In Rust, the `Box` type is a smart pointer used for heap allocation. It's particularly useful when you have large data that you don't want to copy or when you need to ensure a fixed size for a type that is recursive or of unknown size at compile time. Despite its usefulness, `Box` introduces challenges in pattern matching due to Rust’s ownership and borrowing rules.

**Pattern Matching in Rust:**
Pattern matching in Rust is powerful, allowing for concise and readable handling of complex data structures. But when it comes to a `Box`, things get tricky.

Consider this Rust example:
```rs
enum MetaOrData {
    Data(Box<[i32]>),
    Meta(String),
}

fn main() {
    let a = MetaOrData::Data(Box::new([10]));
}
```
`MetaOrData` is an enum with a variant containing a `Box` of an integer array. The objective is to print the first item of the array if it exists. Attempting an implementation yields:

```rs
fn print_first_data_item(it: &MetaOrData) {
    match it {
        MetaOrData::Data(Box([a])) => {
            println!("Box first item {:?}", a); 
        },
        _ => {}
    }
}
```
This intuitive code unfortunately won't compile due to Rust's privacy rules:

```rs
///    |         ^^^ constructor is not visible here due to private field
```
The error occurs because `Box` is a struct with a private field, preventing direct deconstruction in a pattern match.

Despite discussions in the Rust community (e.g., [Rust issue #49733](https://github.com/rust-lang/rust/issues/49733) and [Rust issue #29641](https://github.com/rust-lang/rust/issues/29641)), direct pattern matching against `Box` hasn't been implemented, leading to workarounds:

```rs
fn print_first_data_item(it: &MetaOrData) {
    match it {
        MetaOrData::Data(data) => {
            let slice = &**data;  // Dereferencing the box to access its content
            if let [a] = slice {
                println!("Box first item {:?}", a);
            }
        },
        _ => {}
    }
}
```
Here, we dereference the `Box` to access its content. While effective, this approach can be less intuitive and slightly cumbersome.

**How it should work or OCaml's Approach to Pattern Matching: A Comparison:**
![Code of logic ported from Rust to Ocaml](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqktrfo89hu7hsloyf2h.png)
[Actual code](https://reasonml.github.io/en/try?rrjsx=true&reason=C4TwDgpgBAthwEMD6B7ATkgJgxUC8UAsvAgBQDOwaAlgHYDmAlFAD5QAiOZANtZaXWCNGAbgBQY7vChgatYEgBm1NJSxck1YBBj4oAofgB8UAN5ioUcgHctAYwAW+rc3OXLbTolIBtBAF1mPBM3d0sAKXIAOm4UelIAIgAhFAAPKGVVYCgtHSgEqABqQqsqOnpURU15UgRhcTCAXwt3NiRjfUYW5uaxWUElFTVsRE1tGFIvMh8ARgAGQNEgA)

OCaml’s pattern matching is straightforward, allowing direct deconstruction of lists in match arms, enhancing code readability and simplicity.

**Conclusion:**
While Rust offers robust safety features and powerful pattern matching capabilities, its handling of `Box` types in pattern matches can be restrictive and verbose. Conversely, OCaml provides a more straightforward pattern matching syntax. Integrating Rust features in OCaml with modes, as explored in [Jane Street's blog](https://blog.janestreet.com/oxidizing-ocaml-locality/), shows the potential for combining these languages' strengths.