diff options
Diffstat (limited to 'js/scripting-lang/tutorials/06_Immutable_Tables.md')
-rw-r--r-- | js/scripting-lang/tutorials/06_Immutable_Tables.md | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/js/scripting-lang/tutorials/06_Immutable_Tables.md b/js/scripting-lang/tutorials/06_Immutable_Tables.md new file mode 100644 index 0000000..8502603 --- /dev/null +++ b/js/scripting-lang/tutorials/06_Immutable_Tables.md @@ -0,0 +1,251 @@ +# 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! 🚀 \ No newline at end of file |