about summary refs log tree commit diff stats
path: root/js/scripting-lang/tutorials/13_Error_Handling.md
diff options
context:
space:
mode:
Diffstat (limited to 'js/scripting-lang/tutorials/13_Error_Handling.md')
-rw-r--r--js/scripting-lang/tutorials/13_Error_Handling.md256
1 files changed, 256 insertions, 0 deletions
diff --git a/js/scripting-lang/tutorials/13_Error_Handling.md b/js/scripting-lang/tutorials/13_Error_Handling.md
new file mode 100644
index 0000000..07aff5a
--- /dev/null
+++ b/js/scripting-lang/tutorials/13_Error_Handling.md
@@ -0,0 +1,256 @@
+# Error Handling
+
+## What is Error Handling?
+
+Error handling in Baba Yaga is based on functional programming principles - instead of throwing exceptions, we use pattern matching and return values to handle errors gracefully.
+
+## Basic Error Handling
+
+### Using Pattern Matching
+```plaintext
+/* Handle division by zero */
+safe_divide : x y -> 
+  when y = 0 then "Error: Division by zero"
+  _ then x / y;
+
+/* Test the function */
+..out safe_divide 10 2;   /* 5 */
+..out safe_divide 10 0;   /* Error: Division by zero */
+```
+
+### Return Error Values
+```plaintext
+/* Return structured error information */
+divide_with_error : x y -> 
+  when y = 0 then {error: true, message: "Division by zero", dividend: x}
+  _ then {error: false, result: x / y};
+
+/* Handle the result */
+result : divide_with_error 10 0;
+when result.error is
+  true then ..out "Error: " + result.message
+  false then ..out "Result: " + result.result;
+```
+
+## Assertions for Validation
+
+### Input Validation
+```plaintext
+/* Validate function inputs */
+factorial : n -> 
+  ..assert "n must be non-negative" n >= 0;
+  when n is
+    0 then 1
+    _ then n * (factorial (n - 1));
+
+/* Test validation */
+..out factorial 5;   /* 120 */
+/* factorial -1; */  /* Would fail assertion */
+```
+
+### Data Validation
+```plaintext
+/* Validate table structure */
+validate_user : user -> 
+  ..assert "user must have name" t.has user "name";
+  ..assert "user must have age" t.has user "age";
+  ..assert "age must be positive" user.age > 0;
+  user;
+
+/* Test validation */
+valid_user : {name: "Alice", age: 30};
+invalid_user : {name: "Bob"};  /* Missing age */
+
+validated : validate_user valid_user;
+/* validate_user invalid_user; */  /* Would fail assertion */
+```
+
+## Error Patterns
+
+### Maybe Pattern
+```plaintext
+/* Maybe pattern for optional values */
+find_user : id users -> 
+  when t.has users id then {just: true, value: t.get users id}
+  _ then {just: false};
+
+/* Handle maybe results */
+users : {
+  alice: {name: "Alice", age: 30},
+  bob: {name: "Bob", age: 25}
+};
+
+result : find_user "alice" users;
+when result.just is
+  true then ..out "Found: " + result.value.name
+  false then ..out "User not found";
+
+not_found : find_user "charlie" users;
+when not_found.just is
+  true then ..out "Found: " + not_found.value.name
+  false then ..out "User not found";
+```
+
+### Either Pattern
+```plaintext
+/* Either pattern for success/error */
+parse_number : input -> 
+  parsed : parseInt input;
+  when parsed = NaN then {left: "Invalid number: " + input}
+  _ then {right: parsed};
+
+/* Handle either results */
+valid : parse_number "42";
+when valid.left is
+  _ then ..out "Error: " + valid.left
+  _ then ..out "Success: " + valid.right;
+
+invalid : parse_number "abc";
+when invalid.left is
+  _ then ..out "Error: " + invalid.left
+  _ then ..out "Success: " + invalid.right;
+```
+
+## Error Recovery
+
+### Fallback Values
+```plaintext
+/* Provide fallback values */
+get_config : key default_value config -> 
+  when t.has config key then t.get config key
+  _ then default_value;
+
+/* Use with fallbacks */
+config : {debug: true, timeout: 30};
+debug_mode : get_config "debug" false config;      /* true */
+retries : get_config "retries" 3 config;           /* 3 (fallback) */
+```
+
+### Retry Logic
+```plaintext
+/* Simple retry with exponential backoff */
+retry_operation : operation max_attempts -> 
+  attempt_operation : attempt -> 
+    when attempt > max_attempts then {error: "Max attempts exceeded"}
+    _ then 
+      result : operation;
+      when result.error is
+        true then 
+          delay : power 2 attempt;  /* Exponential backoff */
+          ..out "Attempt " + attempt + " failed, retrying in " + delay + "ms";
+          attempt_operation (attempt + 1)
+        false then result;
+  
+  attempt_operation 1;
+```
+
+## Error Propagation
+
+### Chaining Error Handling
+```plaintext
+/* Chain operations that might fail */
+process_user_data : user_id -> 
+  /* Step 1: Find user */
+  user_result : find_user user_id users;
+  when user_result.just is
+    false then {error: "User not found: " + user_id}
+    _ then 
+      user : user_result.value;
+      
+      /* Step 2: Validate user */
+      validation_result : validate_user user;
+      when validation_result.error is
+        true then {error: "Invalid user data"}
+        _ then 
+          /* Step 3: Process user */
+          processed : process_user user;
+          {success: true, data: processed};
+```
+
+## Testing Error Conditions
+
+### Test Error Cases
+```plaintext
+/* Test both success and error cases */
+test_safe_divide : -> 
+  /* Test successful division */
+  ..assert "10 / 2 = 5" safe_divide 10 2 = 5;
+  
+  /* Test division by zero */
+  error_result : safe_divide 10 0;
+  ..assert "Division by zero returns error" error_result = "Error: Division by zero";
+  
+  ..out "All tests passed";
+
+/* Run the tests */
+test_safe_divide;
+```
+
+### Property-Based Testing
+```plaintext
+/* Test properties of error handling */
+test_divide_properties : -> 
+  /* Property: safe_divide x 1 = x */
+  ..assert "x / 1 = x" safe_divide 42 1 = 42;
+  
+  /* Property: safe_divide x 0 always returns error */
+  ..assert "x / 0 always errors" safe_divide 5 0 = "Error: Division by zero";
+  ..assert "x / 0 always errors" safe_divide -3 0 = "Error: Division by zero";
+  
+  /* Property: safe_divide 0 x = 0 (when x ≠ 0) */
+  ..assert "0 / x = 0" safe_divide 0 5 = 0;
+  
+  ..out "All properties verified";
+```
+
+## Best Practices
+
+### Keep Error Handling Explicit
+```plaintext
+/* Good: Explicit error handling */
+process_data : data -> 
+  when data = null then {error: "No data provided"}
+  _ then 
+    result : transform data;
+    when result.error is
+      true then result
+      false then {success: true, data: result.data};
+
+/* Avoid: Silent failures */
+bad_process : data -> 
+  transform data;  /* What if this fails? */
+```
+
+### Use Descriptive Error Messages
+```plaintext
+/* Good: Descriptive errors */
+validate_age : age -> 
+  when age < 0 then "Age cannot be negative: " + age
+  when age > 150 then "Age seems unrealistic: " + age
+  _ then age;
+
+/* Avoid: Generic errors */
+bad_validate : age -> 
+  when age < 0 then "Invalid input"  /* Too generic */
+  _ then age;
+```
+
+### Handle Errors at the Right Level
+```plaintext
+/* Handle errors where you have context */
+process_user : user_id -> 
+  user : find_user user_id;
+  when user.just is
+    false then 
+      ..emit "user_not_found" {user_id: user_id, timestamp: now()};
+      "User not found"
+    _ then 
+      process_user_data user.value;
+```
+
+## Next Steps
+
+Now that you understand error handling, explore:
+- [Integration Patterns](15_Integration_Patterns.md) for external system error handling
+- [Advanced Combinators](14_Advanced_Combinators.md) for error handling patterns
+- [Best Practices](16_Best_Practices.md) for writing robust code 
\ No newline at end of file