# Immutable Tables with Functional Operations ## What are Immutable Tables? Immutable tables are data structures that **cannot be modified after creation**. All operations on tables return **new tables** rather than modifying the original. ```plaintext /* All table operations return new tables */ original : {a: 1, b: 2, c: 3}; modified : t.set original "d" 4; /* Returns new table */ /* original is unchanged: {a: 1, b: 2, c: 3} */ /* modified is: {a: 1, b: 2, c: 3, d: 4} */ ``` ## Why is This Esoteric? Most programming languages allow direct modification of data structures. Our language enforces **complete immutability** - no mutation operations exist at all. ## Basic Examples ```plaintext /* Create a table */ original : {name: "Alice", age: 30, city: "New York"}; /* All operations return new tables */ with_job : t.set original "job" "Engineer"; with_updated_age : t.set original "age" 31; without_city : t.delete original "city"; /* Original table is unchanged */ /* original is still {name: "Alice", age: 30, city: "New York"} */ ``` ## Table Operations ### Setting Values ```plaintext /* t.set table key value - returns new table with key set */ data : {a: 1, b: 2}; updated : t.set data "c" 3; /* updated: {a: 1, b: 2, c: 3} */ /* data: {a: 1, b: 2} (unchanged) */ ``` ### Deleting Keys ```plaintext /* t.delete table key - returns new table without the key */ data : {a: 1, b: 2, c: 3}; without_b : t.delete data "b"; /* without_b: {a: 1, c: 3} */ /* data: {a: 1, b: 2, c: 3} (unchanged) */ ``` ### Merging Tables ```plaintext /* t.merge table1 table2 - returns new table with combined keys */ table1 : {a: 1, b: 2}; table2 : {c: 3, d: 4}; merged : t.merge table1 table2; /* merged: {a: 1, b: 2, c: 3, d: 4} */ /* table1 and table2 unchanged */ ``` ### Getting Values ```plaintext /* t.get table key - returns value (doesn't modify table) */ data : {name: "Alice", age: 30}; name : t.get data "name"; /* "Alice" */ age : t.get data "age"; /* 30 */ /* data unchanged */ ``` ### Checking Keys ```plaintext /* t.has table key - returns boolean (doesn't modify table) */ data : {name: "Alice", age: 30}; has_name : t.has data "name"; /* true */ has_job : t.has data "job"; /* false */ /* data unchanged */ ``` ## Element-Wise Operations All element-wise operations return new tables: ```plaintext /* map returns new table - @ operator required for higher-order functions */ numbers : {a: 1, b: 2, c: 3}; double : x -> x * 2; doubled : map @double numbers; /* {a: 2, b: 4, c: 6} */ /* numbers unchanged: {a: 1, b: 2, c: 3} */ /* filter returns new table - @ operator required for higher-order functions */ is_greater_than_one : x -> x > 1; filtered : filter @is_greater_than_one numbers; /* {b: 2, c: 3} */ /* numbers unchanged: {a: 1, b: 2, c: 3} */ ``` ## Complex Examples ```plaintext /* Building complex tables immutably */ base_user : {name: "Alice", age: 30}; /* Add multiple properties */ with_email : t.set base_user "email" "alice@example.com"; with_address : t.set with_email "address" "123 Main St"; with_phone : t.set with_address "phone" "555-1234"; /* Or merge with another table */ contact_info : {email: "alice@example.com", phone: "555-1234"}; complete_user : t.merge base_user contact_info; /* Result: {name: "Alice", age: 30, email: "alice@example.com", phone: "555-1234"} */ ``` ## Nested Tables Immutability works with nested table structures: ```plaintext /* Nested table */ user : { name: "Alice", profile: { age: 30, preferences: { theme: "dark", notifications: true } } }; /* Update nested property - creates new nested structure */ updated_preferences : t.set user.profile.preferences "theme" "light"; /* This creates new tables at each level */ /* user unchanged, updated_preferences has new nested structure */ ``` ## Functional Programming Patterns Immutability enables pure functional programming patterns: ```plaintext /* Pure function - no side effects */ update_age : user new_age -> t.set user "age" new_age; /* Multiple updates create new tables */ user1 : {name: "Alice", age: 30}; user2 : update_age user1 31; user3 : update_age user2 32; /* All tables exist independently */ /* user1: {name: "Alice", age: 30} */ /* user2: {name: "Alice", age: 31} */ /* user3: {name: "Alice", age: 32} */ ``` ## When to Use Immutable Tables **Use immutable tables when:** - You want to prevent accidental data modification - You're building functional programming patterns - You need to track data changes over time - You want to ensure thread safety (if applicable) - You're working with complex data transformations **Don't use immutable tables when:** - You need to modify data in place for performance reasons - You're working with very large datasets that can't be copied - You need to perform side effects on data structures ## Common Patterns ```plaintext /* Pattern 1: Building up data structures */ base_config : {debug: false, timeout: 30}; /* Add development settings */ dev_config : t.merge base_config { debug: true, log_level: "verbose" }; /* Add production settings */ prod_config : t.merge base_config { timeout: 60, cache_enabled: true }; /* Pattern 2: Data transformation pipeline */ user_data : {name: "Alice", age: 30, scores: {85, 90, 88}}; /* Transform user data */ with_average : t.set user_data "average_score" (reduce @add 0 user_data.scores / 3); with_grade : t.set with_average "grade" (when with_average.average_score is when with_average.average_score >= 90 then "A" when with_average.average_score >= 80 then "B" _ then "C"); /* Pattern 3: State management */ initial_state : {count: 0, items: {}}; /* State transitions */ increment_state : state -> t.set state "count" (state.count + 1); add_item_state : state item -> t.set state "items" (t.set state.items item.id item); /* Apply transitions */ state1 : increment_state initial_state; state2 : add_item_state state1 {id: "item1", name: "First Item"}; ``` ## Performance Considerations ```plaintext /* Immutability can be expensive for large tables */ large_table : {/* ... many entries ... */}; /* Each operation creates a new copy */ updated1 : t.set large_table "key" "value"; updated2 : t.set updated1 "key2" "value2"; /* This creates multiple copies of the large table */ /* Consider batching operations */ batch_update : table -> t.merge table { key1: "value1", key2: "value2", key3: "value3" }; /* Single operation instead of multiple */ ``` ## Key Takeaways 1. **Complete immutability** - no mutation operations exist 2. **New tables returned** - all operations return new data structures 3. **Original unchanged** - source tables are never modified 4. **Functional patterns** - enables pure functional programming 5. **Composable operations** - operations can be chained safely 6. **@ operator required** - for higher-order functions like `map`, `filter`, `reduce` ## Why This Matters Immutable tables make the language safer and more functional: - **No side effects** - functions can't accidentally modify data - **Predictable behavior** - data never changes unexpectedly - **Functional style** - encourages pure functions and composition - **Debugging ease** - data state is always predictable - **Thread safety** - no shared mutable state issues This feature makes the language feel more like pure functional languages like Haskell! 🚀