๐Ÿฆ€ Functional Rust
๐ŸŽฌ Rust Ownership in 30 seconds Visual walkthrough of ownership, moves, and automatic memory management.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Each value in Rust has exactly one owner โ€” when the owner goes out of scope, the value is dropped

โ€ข Assignment moves ownership by default; the original binding becomes invalid

โ€ข Borrowing (&T / &mut T) lets you reference data without taking ownership

โ€ข The compiler enforces: many shared references OR one mutable reference, never both

โ€ข No garbage collector needed โ€” memory is freed deterministically at scope exit

101: Move Semantics

Difficulty: Intermediate Category: Ownership Concept: Move: ownership transfer Key Insight: OCaml's GC handles memory; Rust moves ownership โ€” after a move, the original binding is invalid
// 101: Move Semantics
// Ownership transfer โ€” after move, original is invalid

// Approach 1: Move with String (heap-allocated)
fn take_ownership(s: String) -> usize {
    s.len() // s is consumed here
}

fn demonstrate_move() {
    let s = String::from("hello");
    let len = take_ownership(s);
    // println!("{}", s); // ERROR: s has been moved!
    assert_eq!(len, 5);
}

// Approach 2: Copy types don't move
fn demonstrate_copy() {
    let x = 42;
    let y = x; // copy, not move โ€” x is still valid
    assert_eq!(x, 42);
    assert_eq!(y, 42);
}

// Approach 3: Move in collections
fn demonstrate_vec_move() {
    let v1 = vec![1, 2, 3];
    let v2 = v1; // v1 is moved to v2
    // println!("{:?}", v1); // ERROR: v1 has been moved
    assert_eq!(v2, vec![1, 2, 3]);
}

// Return value transfers ownership back
fn create_string() -> String {
    let s = String::from("created");
    s // ownership transferred to caller
}

fn main() {
    demonstrate_move();
    demonstrate_copy();
    demonstrate_vec_move();
    let s = create_string();
    println!("Created: {}", s);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_take_ownership() {
        let s = String::from("hello");
        assert_eq!(take_ownership(s), 5);
    }

    #[test]
    fn test_copy_types() {
        let x = 42;
        let y = x;
        assert_eq!(x + y, 84);
    }

    #[test]
    fn test_vec_move() {
        let v1 = vec![1, 2, 3];
        let v2 = v1;
        assert_eq!(v2.len(), 3);
    }

    #[test]
    fn test_return_ownership() {
        let s = create_string();
        assert_eq!(s, "created");
    }
}
(* 101: Move Semantics *)
(* OCaml: GC handles everything. No move semantics. *)

(* Approach 1: OCaml โ€” values are freely shared via GC *)
let use_string s = String.length s
let share_freely () =
  let s = "hello" in
  let a = use_string s in   (* s is still valid *)
  let b = use_string s in   (* s is still valid *)
  a + b

(* Approach 2: Simulating ownership with linear types *)
(* OCaml doesn't enforce this, but we can model it *)
type 'a owned = Owned of 'a | Moved

let take (r : 'a owned ref) =
  match !r with
  | Owned v -> r := Moved; v
  | Moved -> failwith "value already moved"

let demo_simulated_move () =
  let r = ref (Owned "hello") in
  let s = take r in
  (* take r again would fail *)
  String.length s

(* Tests *)
let () =
  assert (share_freely () = 10);
  assert (demo_simulated_move () = 5);
  Printf.printf "โœ“ All tests passed\n"

๐Ÿ“Š Detailed Comparison

Core Insight

OCaml's GC handles memory; Rust moves ownership โ€” after a move, the original binding is invalid

OCaml Approach

  • See example.ml for implementation

Rust Approach

  • See example.rs for implementation

Comparison Table

FeatureOCamlRust
Seeexample.mlexample.rs