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

408: Clone vs Copy Semantics

Difficulty: 2 Level: Intermediate Two duplication models โ€” implicit bitwise copy for small value types, explicit deep clone for everything else.

The Problem This Solves

When you assign a value in Rust, ownership moves by default. After `let b = a;`, `a` is gone โ€” moved into `b`. This is correct for heap-owning types like `String` and `Vec` where silent copying would be expensive and surprising. But for simple integers and booleans, moving doesn't make sense: they're tiny, they contain no heap resources, and copying them is what you always want. `Copy` marks types that are safe to duplicate by bit-copying โ€” integers, `bool`, `char`, `f64`, tuples of `Copy` types, references. After `let b = a;` on a `Copy` type, both `a` and `b` are valid. No heap involved, no destructor to worry about, just bits. `Clone` is the explicit version. Call `.clone()` to duplicate anything that implements it. For `String`, clone allocates a new heap buffer and copies the bytes. For complex nested types, it recurses. It's always opt-in, always visible in code, and potentially expensive โ€” which is exactly the design intent.

The Intuition

`Copy` = assign and the original still works (implicit bitwise copy); `Clone` = call `.clone()` explicitly when you need a deliberate duplicate that may allocate.

How It Works in Rust

// Copy types โ€” assignment copies, original still valid
let x: i32 = 42;
let y = x;       // x is COPIED, not moved
println!("{}", x); // still valid

// Tuple of Copy types is also Copy
let point = (1.0f64, 2.0f64);
let p2 = point;  // copied
println!("{:?}", point); // still valid

// Clone โ€” explicit, potentially expensive
#[derive(Debug, Clone)]
struct Config { name: String, values: Vec<i32> }

let cfg = Config { name: "main".to_string(), values: vec![1, 2, 3] };
let cfg2 = cfg.clone();  // allocates new String + new Vec
// cfg is still valid, cfg2 is an independent copy

// Can't be Copy if it owns heap memory
// #[derive(Copy)] on Config would FAIL โ€” String doesn't implement Copy

// Custom Copy type โ€” must also implement Clone
#[derive(Debug, Clone, Copy)]
struct Point { x: f64, y: f64 }

let p = Point { x: 1.0, y: 2.0 };
let p2 = p;  // copied โ€” no .clone() needed
process(p);  // p still valid here
1. `Copy` is a marker trait โ€” no methods, just signals "bitwise copy is safe." 2. `Clone` has the `.clone()` method โ€” implement it for deep duplication. 3. `Copy` requires `Clone` (all Copy types must also be Clone). 4. Types with `Drop` implementations cannot be `Copy` (they manage resources).

What This Unlocks

Key Differences

ConceptOCamlRust
AssignmentAlways copies (persistent data structures) or aliasesMoves by default, copies only for `Copy` types
Explicit duplicationStructural sharing (immutable), `copy` module`.clone()` โ€” always explicit, always visible
Primitive typesAll immutable values, copy-on-use`i32`, `f64`, `bool`, `char` โ€” `Copy`
String`string` is immutable, assignment is fine`String` moves; `&str` is `Copy`
Resource managementGC handles it`Copy` explicitly forbidden for types with `Drop`
// Clone vs Copy semantics in Rust

// Copy: bitwise, implicit, no destructor
#[derive(Debug, Clone, Copy, PartialEq)]
struct Vector2D { x: f32, y: f32 }

impl Vector2D {
    fn magnitude(&self) -> f32 { (self.x * self.x + self.y * self.y).sqrt() }
    fn add(self, other: Vector2D) -> Vector2D {
        Vector2D { x: self.x + other.x, y: self.y + other.y }
    }
}

// Clone only: has heap allocation
#[derive(Debug, Clone)]
struct DNA {
    sequence: String,
    species: String,
}

impl DNA {
    fn new(seq: &str, species: &str) -> Self {
        DNA { sequence: seq.to_string(), species: species.to_string() }
    }

    fn mutate(&mut self, pos: usize, base: char) {
        if pos < self.sequence.len() {
            let mut chars: Vec<char> = self.sequence.chars().collect();
            chars[pos] = base;
            self.sequence = chars.into_iter().collect();
        }
    }
}

// How Drop prevents Copy
struct Resource { name: String }
impl Drop for Resource {
    fn drop(&mut self) { println!("Dropping: {}", self.name); }
}
// Cannot: impl Copy for Resource (has Drop)

fn demonstrate_copy() {
    let v1 = Vector2D { x: 3.0, y: 4.0 };
    let v2 = v1;       // Copy: v1 is still valid!
    let v3 = v1;       // Can copy again
    println!("v1: {:?}, v2: {:?}, v3: {:?}", v1, v2, v3);
    println!("Magnitude: {:.2}", v1.magnitude());
    let sum = v1.add(v2); // v1 and v2 still valid after
    println!("Sum: {:?}", sum);
}

fn demonstrate_clone() {
    let dna1 = DNA::new("ATCGATCG", "human");
    let mut dna2 = dna1.clone(); // explicit clone
    // dna1 is still valid
    dna2.mutate(2, 'G');
    println!("dna1: {}", dna1.sequence); // unchanged
    println!("dna2: {}", dna2.sequence); // mutated copy
}

fn demonstrate_move() {
    let s1 = String::from("hello"); // not Copy
    let s2 = s1;                    // MOVED: s1 is no longer valid
    // println!("{}", s1);          // Error: use of moved value
    println!("s2: {}", s2);

    let s3 = s2.clone();            // Clone: both valid
    println!("s2: {}, s3: {}", s2, s3);
}

fn main() {
    println!("=== Copy ===");
    demonstrate_copy();
    println!("\n=== Clone ===");
    demonstrate_clone();
    println!("\n=== Move ===");
    demonstrate_move();

    {
        let r = Resource { name: "file".to_string() };
        println!("Resource created: {}", r.name);
    } // drop called here
}

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

    #[test]
    fn test_copy() {
        let v = Vector2D { x: 1.0, y: 0.0 };
        let v2 = v;
        assert_eq!(v, v2); // v still valid
    }

    #[test]
    fn test_clone_independence() {
        let d1 = DNA::new("ATCG", "mouse");
        let mut d2 = d1.clone();
        d2.mutate(0, 'G');
        assert_eq!(d1.sequence, "ATCG"); // unchanged
        assert_eq!(d2.sequence, "GTCG");
    }
}
(* Clone vs Copy semantics in OCaml *)

(* All OCaml values are implicitly copyable via GC *)

(* Simulate Copy-like semantics with simple values *)
let demonstrate_copy () =
  let x = 42 in
  let y = x in  (* Both valid โ€” OCaml integers are like Rust Copy *)
  Printf.printf "x=%d y=%d\n" x y

(* Simulate Clone-like with explicit copy functions *)
type dna = { sequence: string; length: int }

let clone_dna dna =
  { sequence = String.copy dna.sequence; length = dna.length }

let () =
  demonstrate_copy ();
  let dna1 = { sequence = "ATCG"; length = 4 } in
  let dna2 = clone_dna dna1 in
  Printf.printf "DNA1: %s  DNA2: %s\n" dna1.sequence dna2.sequence;
  Printf.printf "Same reference: %b\n" (dna1.sequence == dna2.sequence)