๐Ÿฆ€ 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

102: Clone and Copy

Difficulty: 2 Level: Intermediate Copy types are silently duplicated when passed; Clone types require an explicit `.clone()` โ€” making expensive copies visible.

The Problem This Solves

Languages with GC (Python, Java, OCaml) make all copies implicit. You never think about whether copying is cheap or expensive โ€” the runtime handles it. This is convenient, but it hides costs. A Python function that receives a list and "accidentally" modifies it can surprise the caller. A Java method that stores a reference to your object can mutate it later without your knowledge. Rust separates two fundamentally different things: cheap stack copies (integers, booleans โ€” a handful of bytes, trivially duplicated) and expensive heap copies (strings, vectors โ€” arbitrary amounts of data that require allocating new memory). The `Copy` trait marks the first kind. The `Clone` trait handles the second โ€” and it requires you to call `.clone()` explicitly, making the cost visible in your code. This design means: when you see `.clone()` in Rust code, you know a potentially expensive heap allocation is happening. When you don't see it, you know the copy is cheap. No hidden costs.

The Intuition

Types that fit entirely on the stack (`Copy`) are silently duplicated when passed; types that own heap data (`Clone`) require explicit `.clone()` because the compiler won't hide an expensive allocation from you.

How It Works in Rust

// Copy types: assignment and passing create silent copies
let x: i32 = 42;
let y = x;          // copy, not move โ€” x is still valid
println!("{}", x);  // works fine

// This applies to: i8..i128, u8..u128, f32, f64, bool, char,
// tuples/arrays of Copy types, raw pointers, references

// Clone types: heap data requires explicit .clone()
let s1 = String::from("hello");
// let s2 = s1;     // MOVE โ€” s1 is gone
let s2 = s1.clone(); // CLONE โ€” s1 is still valid, s2 is a fresh copy
println!("{} {}", s1, s2); // both work

// Structs: all fields must be Copy to derive Copy
#[derive(Copy, Clone)]
struct Point { x: f64, y: f64 }  // f64 is Copy โ†’ Point can be Copy

// This can't be Copy โ€” String is not Copy
#[derive(Clone)]
struct Person { name: String, age: u32 }
// Can only derive Clone, not Copy

let p1 = Person { name: "Alice".to_string(), age: 30 };
let p2 = p1.clone(); // explicit deep copy โ€” allocates new String
// let p3 = p1;      // would be a MOVE, not copy

// Vec<T> is Clone (not Copy) โ€” cloning copies all elements
let v1 = vec![1, 2, 3];
let v2 = v1.clone(); // new allocation, copies all elements

What This Unlocks

Key Differences

ConceptOCamlRust
Copying primitivesImplicit (GC pointer or bitwise)Implicit via `Copy` trait
Copying heap dataImplicit (GC manages sharing)Explicit `.clone()`
Custom struct copyShallow copy via `{...with ...}` or GC-sharedMust derive `Copy` (all fields must be `Copy`)
Visibility of costHidden by GCVisible โ€” `.clone()` = allocation
Sharing by defaultYes (GC refs)No โ€” ownership is exclusive
// Example 102: Clone vs Copy Traits
//
// Copy: bitwise copy, implicit, for simple stack types (i32, f64, bool, etc.)
// Clone: explicit deep copy via .clone(), for heap types (String, Vec, etc.)

// Approach 1: Copy types โ€” implicit duplication
fn approach1() {
    let x: i32 = 42;
    let y = x; // Copy โ€” both valid
    assert_eq!(x, y);
    
    let p = (1.0_f64, 2.0_f64); // tuples of Copy types are Copy
    let q = p;
    assert_eq!(p, q);
    println!("Copy types: x={}, y={}, p={:?}, q={:?}", x, y, p, q);
}

// Approach 2: Clone for heap types
fn approach2() {
    let s1 = String::from("hello");
    let s2 = s1.clone(); // explicit deep copy
    assert_eq!(s1, s2);
    
    let v1 = vec![1, 2, 3];
    let v2 = v1.clone();
    assert_eq!(v1, v2);
    println!("Cloned: s1={}, s2={}, v1={:?}, v2={:?}", s1, s2, v1, v2);
}

// Approach 3: Deriving Copy and Clone for custom types
#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
    x: f64,
    y: f64,
}

#[derive(Debug, Clone, PartialEq)]
struct Label {
    name: String,       // String is not Copy, so Label can't be Copy
    position: Point,    // Point is Copy
}

fn translate(p: Point, dx: f64, dy: f64) -> Point {
    Point { x: p.x + dx, y: p.y + dy }
}

fn approach3() {
    // Point is Copy โ€” no move
    let origin = Point { x: 0.0, y: 0.0 };
    let moved = translate(origin, 1.0, 2.0);
    assert_eq!(origin.x, 0.0); // still valid!
    println!("Origin: {:?}, Moved: {:?}", origin, moved);
    
    // Label must be cloned
    let label = Label { name: "Start".into(), position: origin };
    let label2 = label.clone();
    assert_eq!(label, label2);
    println!("Label: {:?}, Clone: {:?}", label, label2);
}

fn main() {
    println!("=== Approach 1: Copy Types ===");
    approach1();
    println!("\n=== Approach 2: Clone for Heap Types ===");
    approach2();
    println!("\n=== Approach 3: Custom Copy/Clone ===");
    approach3();
}

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

    #[test]
    fn test_copy_semantics() {
        let x = 42i32;
        let y = x;
        assert_eq!(x, y);
    }

    #[test]
    fn test_clone_string() {
        let s = String::from("test");
        let s2 = s.clone();
        assert_eq!(s, s2);
        // Both are independent
        drop(s);
        assert_eq!(s2, "test");
    }

    #[test]
    fn test_point_is_copy() {
        let p = Point { x: 1.0, y: 2.0 };
        let q = p; // Copy
        assert_eq!(p, q);
    }

    #[test]
    fn test_label_needs_clone() {
        let l = Label { name: "A".into(), position: Point { x: 0.0, y: 0.0 } };
        let l2 = l.clone();
        assert_eq!(l.name, l2.name);
    }

    #[test]
    fn test_vec_clone_independence() {
        let mut v1 = vec![1, 2, 3];
        let v2 = v1.clone();
        v1.push(4);
        assert_eq!(v1.len(), 4);
        assert_eq!(v2.len(), 3); // independent
    }
}
(* Example 102: Clone vs Copy โ€” OCaml Implicit Sharing โ†’ Rust Explicit Cloning *)

(* In OCaml, all values are implicitly shared via GC.
   There's no distinction between "shallow copy" and "deep copy" at the language level. *)

(* Approach 1: Sharing structured data โ€” always implicit *)
type point = { x : float; y : float }

let translate p dx dy =
  { x = p.x +. dx; y = p.y +. dy }

let approach1 () =
  let origin = { x = 0.0; y = 0.0 } in
  let moved = translate origin 1.0 2.0 in
  (* origin is still valid โ€” OCaml creates new record, GC manages old *)
  assert (origin.x = 0.0);
  assert (moved.x = 1.0);
  Printf.printf "Origin: (%.1f, %.1f), Moved: (%.1f, %.1f)\n"
    origin.x origin.y moved.x moved.y

(* Approach 2: List sharing โ€” structural sharing *)
let approach2 () =
  let xs = [1; 2; 3] in
  let ys = 0 :: xs in  (* ys shares the tail with xs *)
  assert (List.length xs = 3);
  assert (List.length ys = 4);
  Printf.printf "xs = %s, ys = %s\n"
    (String.concat "; " (List.map string_of_int xs))
    (String.concat "; " (List.map string_of_int ys))

(* Approach 3: Deep copy via Marshal (rarely needed) *)
let deep_copy x =
  Marshal.from_string (Marshal.to_string x [Marshal.Closures]) 0

let approach3 () =
  let data = [| [1; 2]; [3; 4] |] in
  let copy = deep_copy data in
  assert (data = copy);
  Printf.printf "Deep copied array of lists\n"

let () =
  approach1 ();
  approach2 ();
  approach3 ();
  Printf.printf "โœ“ All tests passed\n"

๐Ÿ“Š Detailed Comparison

Comparison: Clone vs Copy

Implicit Copying

OCaml โ€” everything is implicitly shared:

๐Ÿช Show OCaml equivalent
let x = 42 in
let y = x in  (* shared, GC manages *)
(x, y)

Rust โ€” only `Copy` types are implicit:

let x: i32 = 42;
let y = x;  // Copy โ€” both valid
// String is NOT Copy:
let s = String::from("hi");
let t = s;  // Move! s is gone

Explicit Deep Copy

OCaml โ€” new record = new allocation:

๐Ÿช Show OCaml equivalent
type point = { x : float; y : float }
let p = { x = 1.0; y = 2.0 } in
let q = { p with y = 3.0 } in  (* new record *)
(p, q)  (* both valid *)

Rust โ€” `.clone()` for heap types:

let s1 = String::from("hello");
let s2 = s1.clone();  // explicit deep copy
println!("{} {}", s1, s2);  // both valid

Custom Types

OCaml โ€” all types work the same:

๐Ÿช Show OCaml equivalent
type label = { name : string; pos : point }
let l = { name = "A"; pos = { x = 0.0; y = 0.0 } } in
let l2 = { l with name = "B" } in
(l, l2)

Rust โ€” must derive traits:

#[derive(Clone, Copy)]  // Only if ALL fields are Copy
struct Point { x: f64, y: f64 }

#[derive(Clone)]  // Can't be Copy (String isn't Copy)
struct Label { name: String, position: Point }

let l = Label { name: "A".into(), position: Point { x: 0.0, y: 0.0 } };
let l2 = l.clone();  // must clone explicitly