Patterns#

Common patterns and idioms in Bark.

Error Handling#

Demonstrates error checking, zero value semantics, and validation patterns using present?(), absent?(), and return?().

patterns/error_handling.bark View on GitLab
// Error Checking Examples
// Demonstrates error checking and zero value semantics

// =============================================================================
// Error Checking with present?() and absent?()
// =============================================================================

fn check_error_present(err error) {
  err > absent?() > println?("Operation succeeded") > return()

  err > err_msg() > eprintln()
}

fn check_error_absent(err error) {
  // Check if error is absent (empty map)
  err > absent?() > println?("No error occurred")
}

// =============================================================================
// Zero Values
// =============================================================================

// Each type has a defined zero value:
// - string: ""
// - bool: false
// - int: 0
// - uint: 0
// - float: 0.0
// - error: {} (empty error map)
// - map: {}
// - array: []
// - regex: (must be explicitly created)

fn demonstrate_zero_values() {
  "" > empty_string          // Zero value for string
  false > zero_bool          // Zero value for bool
  0 > zero_int               // Zero value for int
  0.0 > zero_float           // Zero value for float
  {} > empty_map             // Zero value for map
  [] > empty_array           // Zero value for array
  {} > empty_error           // Zero value for error (success)

  // Note: empty collections use size() for maps, len() for arrays
  empty_map > size() > println()      // 0
  empty_array > len() > println()     // 0
  empty_error > absent?() > println() // true (no error)
}

// =============================================================================
// Error Type and Checking
// =============================================================================

// error type uses map representation internally
// Empty error map {} means "no error" (success)
// Non-empty error map means an error occurred

fn successful_operation() {
  // Return empty error to indicate success
  return({}, "result")
}(error, string)

fn failed_operation() {
  // Return error with message
  err("operation failed") > failure
  return(failure, "")
}(error, string)

fn check_operation_result(err error, result string) {
  err > absent?() > continue?() > result > println() > return()

  err > err_msg() > eprintln()
}

// =============================================================================
// Error Propagation with return?()
// =============================================================================

fn process_with_propagation(input string) {
  // Validate input
  input > validate() > (err1, validated)
  err1 > return?(err1, "")  // If err1 is present, return immediately with zero values

  // Process validated input - only executes if err1 was absent
  validated > transform() > (err2, result)
  err2 > return?(err2, "")

  // Return success
  return({}, result)
}(error, string)

// =============================================================================
// Collections and Zero Values
// =============================================================================

// Maps error on missing keys - use map.get_or or check first
fn map_missing_key() {
  {"name": "alice"} > user

  // Use map.get_or to handle missing keys gracefully
  user > map.get_or("age", 0) > age
  // age is now 0 (the default)

  age > eq?(0) > (isZero bool) {
    isZero > not() > return?()
    println("Age not found or is zero")
  }()
}

// Use get_or to provide explicit default
fn map_with_default() {
  {"name": "alice"} > user

  // Provide explicit default value
  user > map.get_or("age", 25) > age
  // age is now 25
}

// Use map.key_present?() to distinguish missing keys from zero values
fn check_key_exists() {
  {"name": "alice", "age": 0} > user
  user > map.key_present?("age") > println?("Age key exists (value may be 0)")
  user > map.key_absent?("email") > println?("Email key does not exist")
}

// Array access - invalid index logs to stderr but program continues
fn array_access() {
  [1, 2, 3] > items

  // Valid access
  items > get(0) > first
  first > println()

  // Invalid access - logs error to stderr, chain stops, but program continues
  items > get(10) > println()

  // This line still runs
  println("Program continues after invalid access")
}

// =============================================================================
// Truthy and Falsy Values
// =============================================================================

// Falsy values: false, 0, 0.0, "", {}, []
// All other values are truthy

fn check_truthiness() {
  // Empty string is falsy
  "" > empty
  empty > present?() > (p bool) {
    p > not() > return?()
    println("Empty string is truthy (won't print)")
  }()
  empty > absent?() > (a bool) {
    a > not() > return?()
    println("Empty string is falsy")
  }()

  // Non-empty string is truthy
  "hello" > greeting
  greeting > present?() > (p2 bool) {
    p2 > not() > return?()
    println("Non-empty string is truthy")
  }()
}

fn check_collection_truthiness() {
  // Empty collections are falsy
  {} > empty_map
  empty_map > present?() > (p1 bool) {
    p1 > not() > return?()
    println("Empty map is truthy (won't print)")
  }()
  empty_map > absent?() > (a1 bool) {
    a1 > not() > return?()
    println("Empty map is falsy")
  }()

  [] > empty_array
  empty_array > present?() > (p2 bool) {
    p2 > not() > return?()
    println("Empty array is truthy (won't print)")
  }()
  empty_array > absent?() > (a2 bool) {
    a2 > not() > return?()
    println("Empty array is falsy")
  }()

  // Non-empty collections are truthy
  {"key": "value"} > mymap
  mymap > present?() > (p3 bool) {
    p3 > not() > return?()
    println("Non-empty map is truthy")
  }()
}

fn check_error_truthiness() {
  // Empty error (no error) is falsy
  {} > success
  success > present?() > (p1 bool) {
    p1 > not() > return?()
    println("Success error is truthy (won't print)")
  }()
  success > absent?() > (a1 bool) {
    a1 > not() > return?()
    println("Success error is falsy")
  }()

  // Non-empty error (has error) is truthy
  err("failed") > e
  e > present?() > (p2 bool) {
    p2 > not() > return?()
    e > err_msg() > msg
    println("{0} - Error is truthy", msg)
  }()
}

// =============================================================================
// Empty vs Non-Empty Collections
// =============================================================================

fn demonstrate_empty_collections() {
  // Empty collections have length 0
  {} > empty_map
  empty_map > size() > println()       // 0
  empty_map > empty?() > println()     // true

  [] > empty_array
  empty_array > len() > println()      // 0
  empty_array > empty?() > println()   // true

  // Empty error (success) is also empty
  {} > success
  success > absent?() > println()      // true (no error)
  success > size() > println()         // 0
}

// =============================================================================
// return?() and Zero Values
// =============================================================================

// When return?() causes early return, values must be explicitly provided
fn multi_return_with_return(input string) {
  // If validation fails, return?() returns (err, "", 0)
  input > validate() > (err, result)
  err > return?(err, "", 0)  // Early return with explicit values if err is truthy

  // Continue processing only if err was falsy
  result > transform() > processed
  return({}, processed, 42)
}(error, string, int)

// =============================================================================
// Real-World Example: Optional Fields
// =============================================================================

fn get_user_display_name(user map) {
  // Try to get nickname first, use map.get_or to handle missing
  user > map.get_or("nickname", "") > nickname

  // If nickname is present (non-empty), return it
  nickname > present?() > return?(nickname)

  // Otherwise return name or Anonymous
  user > map.get_or("name", "Anonymous") > return()
}(string)

// Better pattern: use get_or with fallback chain
fn get_user_display_name_better(user map) {
  // Try nickname first
  user > map.get_or("nickname", "") > nickname

  // If nickname is present, return it
  nickname > present?() > return?(nickname)

  // Fall back to name, then to "Anonymous"
  user > map.get_or("name", "Anonymous") > return()
}(string)

// =============================================================================
// Real-World Example: Validation with Error Checking
// =============================================================================

fn validate_user_input(data map) {
  // Check required fields using map.key_absent?()
  err("email is required") > email_err
  data > map.key_absent?("email") > return?(email_err, {})

  err("username is required") > username_err
  data > map.key_absent?("username") > return?(username_err, {})

  data > get("email") > email
  data > get("username") > username

  // Optional field with default
  data > map.get_or("age", 0) > age

  // Build validated user
  return({}, {"email": email, "username": username, "age": age})
}(error, map)

// =============================================================================
// Real-World Example: Safe Chain with Error Checking
// =============================================================================

fn safe_user_processing(user_id int) {
  // Fetch user from database
  user_id > fetch_user() > (err1, user)
  err1 > return?(err1, "")

  // Validate user data
  user > validate_user() > (err2, validated)
  err2 > return?(err2, "")

  // Process validated user
  validated > process_user() > (err3, result)
  err3 > return?(err3, "")

  // Return success
  return({}, result)
}(error, map)

// =============================================================================
// Execute Functions
// =============================================================================

println("=== Error Checking ===")

// Error checking with present?() and absent?()
println("check_error_present(err(\"test error\")): ")
err("test error") > check_error_present()

println("check_error_present({}): ")
{} > check_error_present()

println("check_error_absent({}): ")
{} > check_error_absent()

// Zero values demonstration
println("demonstrate_zero_values(): ")
demonstrate_zero_values()

// Operation results - returns (error, string) tuple
println("successful_operation(): ")
successful_operation() > (err_val error, result string) {
  println(err_val)
  println(result)
}()

println("failed_operation(): ")
failed_operation() > (err_val error, result string) {
  println(err_val)
  println(result)
}()

println("check_operation_result({}, \"success result\"): ")
{} > check_operation_result("success result")

println("check_operation_result(err(\"failed\"), \"\"): ")
err("failed") > check_operation_result("")

// Map key checking
println("map_missing_key(): ")
map_missing_key()

println("map_with_default(): ")
map_with_default()

println("check_key_exists(): ")
check_key_exists()

// Array access
println("array_access(): ")
array_access()

// Truthiness
println("check_truthiness(): ")
check_truthiness()

println("check_collection_truthiness(): ")
check_collection_truthiness()

println("check_error_truthiness(): ")
check_error_truthiness()

// Empty collections
println("demonstrate_empty_collections(): ")
demonstrate_empty_collections()

// User display name
{"name": "John", "nickname": "Johnny"} > get_user_display_name() > display1
println("get_user_display_name({{\"name\": \"John\", \"nickname\": \"Johnny\"}}): {0}", display1)

{"name": "John"} > get_user_display_name() > display2
println("get_user_display_name({{\"name\": \"John\"}}): {0}", display2)

{"name": "John"} > get_user_display_name_better() > display3
println("get_user_display_name_better({{\"name\": \"John\"}}): {0}", display3)

// Validation - returns (error, map) tuple
println("validate_user_input({\"email\": \"test@example.com\", \"username\": \"john\"}): ")
{"email": "test@example.com", "username": "john"} > validate_user_input() > (err_v error, user map) {
  println(err_v)
  println(user)
}()

println("validate_user_input({\"username\": \"john\"}): ")
{"username": "john"} > validate_user_input() > (err_v error, user map) {
  println(err_v)
  println(user)
}()

// Note: The following functions depend on undefined helpers (validate, fetch_user, etc.):
// - process_with_propagation
// - multi_return_with_return
// - safe_user_processing
// These demonstrate patterns but are not runnable.

println("=== End of Error Checking Examples ===")

Memoization#

The mfn keyword creates memoized functions that automatically cache results based on arguments. Includes fibonacci, factorial, and ackermann examples.

patterns/memoization.bark View on GitLab
// Memoization Example
//
// Demonstrates the mfn keyword for memoized functions.
// Memoized functions automatically cache results based on arguments.

// Fibonacci - classic example of memoization benefits
// Without memoization: O(2^n) time complexity
// With memoization: O(n) time complexity
mfn fib(n int) {
    n > lte?(1) > return?(n)
    n > sub(1) > fib() > a
    n > sub(2) > fib() > b
    a > add(b) > return()
}(int)

println("Fibonacci sequence (memoized):")
array.range(0, 20) > each((arr array, i int) {
    arr > get(i) > n
    n > fib() > result
    println("fib({0}) = {1}", n, result)
}())

println()

// Factorial - another common recursive example
mfn factorial(n int) {
    n > lte?(1) > return?(1)
    n > sub(1) > factorial() > prev
    n > mul(prev) > return()
}(int)

println("Factorials (memoized):")
array.range(0, 12) > each((arr array, i int) {
    arr > get(i) > n
    n > factorial() > result
    println("{0}! = {1}", n, result)
}())

println()

// Ackermann function - extremely recursive
// Without memoization, even small inputs take forever
mfn ackermann(m int, n int) {
    // Base case: m = 0 -> return n + 1
    m > eq?(0) > (is_zero bool) {
        is_zero > eq?(false) > return?()
        n > add(1) > return()
    }(int) > base_result
    base_result > present?() > return?(base_result)

    // Case: n = 0 -> return A(m-1, 1)
    n > eq?(0) > (is_n_zero bool) {
        is_n_zero > eq?(false) > return?()
        m > sub(1) > ackermann(1) > return()
    }(int) > zero_result
    zero_result > present?() > return?(zero_result)

    // Recursive case: A(m-1, A(m, n-1))
    m > sub(1) > m_minus_1
    n > sub(1) > n_minus_1
    m > ackermann(n_minus_1) > inner
    m_minus_1 > ackermann(inner) > return()
}(int)

fn print_ackermann(m int, n int) {
    m > ackermann(n) > result
    println("A({0}, {1}) = {2}", m, n, result)
}()

println("Ackermann function (memoized):")
0 > print_ackermann(5)
1 > print_ackermann(5)
2 > print_ackermann(5)
3 > print_ackermann(5)
// A(4, 1) = 65533 - even with memoization this is large!
3 > print_ackermann(10)

println()
println("Memoization complete!")

Parallel Processing#

Bark’s parallel processing capabilities using parallel, parallel_all, parallel_limited, parallel_race, and parallel_strict.

patterns/parallel.bark View on GitLab
// Parallel Processing in bark
//
// This example demonstrates bark's parallel processing capabilities using
// builtin functions for concurrent execution.

fn main() {
  println("=== Parallel Processing Examples ===")
  println("")

  // Example 1: Basic parallel processing
  example_basic_parallel()

  // Example 2: Parallel with error handling
  example_parallel_with_errors()

  // Example 3: Parallel all (independent operations)
  example_parallel_all()

  // Example 4: Limited concurrency (worker pool)
  example_parallel_limited()

  // Example 5: Race pattern (first to complete)
  example_parallel_race()

  // Example 6: Strict mode (fail-fast)
  example_parallel_strict()

  return()
}(int)

// Example 1: Basic parallel processing
fn example_basic_parallel() {
  println("1. Basic Parallel Processing")
  println("   Processing array elements in parallel...")

  // Process numbers in parallel, adding 10 to each
  [1, 2, 3, 4, 5] > parallel((x int) {
    x > add(10) > result
    return({}, result)
  }(map, int)) > result_tuple

  result_tuple > get(0) > errors
  result_tuple > get(1) > results

  // Check if all succeeded and report
  errors > all_absent?() > all_ok
  all_ok > eq?(true) > (ok bool) {
    ok > return?("   All operations succeeded!")
    return("   Some operations failed!")
  }(string) > msg
  msg > println()

  println("   Results: {0}", results)
  println("")

  return()
}(int)

// Example 2: Parallel with error handling
fn example_parallel_with_errors() {
  println("2. Parallel Processing with Errors")
  println("   Some operations will fail...")

  // Simulate operations where some fail
  [1, 2, 3, 4, 5] > parallel((x int) {
    // Fail on even numbers
    x > math.even?() > is_even
    is_even > (cond bool) {
      err("Failed on even number") > e
      cond > return?(e, 0)
      return({}, x)
    }(map, int)
  }(map, int)) > result_tuple

  result_tuple > get(0) > errors
  result_tuple > get(1) > results

  // Check results and report
  errors > all_absent?() > all_ok
  errors > all_present?() > all_failed

  all_ok > not() > eq?(true) > (has_errors bool) {
    has_errors > return?("   Some operations failed (expected)")
    return("")
  }(string) > msg1
  msg1 > len() > gt?(0) > (has_msg bool) {
    has_msg > return?()
    return()
  }()
  msg1 > println()

  all_failed > eq?(true) > (failed bool) {
    failed > return?("   All operations failed")
    return("   Mix of success and failure")
  }(string) > msg2
  msg2 > println()

  println("   Successful results: {0}", results)
  println("")

  return()
}(int)

// Example 3: Parallel all - execute independent operations
fn example_parallel_all() {
  println("3. Parallel All (Independent Operations)")
  println("   Running multiple independent tasks...")

  [
    (dummy int) {
      // Task 1: Sum numbers
      15 > result
      return({}, result)
    }(map, int),
    (dummy int) {
      // Task 2: Multiply numbers
      24 > result
      return({}, result)
    }(map, int),
    (dummy int) {
      // Task 3: Simple calculation
      10 > add(5) > mul(2) > result
      return({}, result)
    }(map, int)
  ] > parallel_all() > result_tuple

  result_tuple > get(1) > results

  results > get(0) > t1
  results > get(1) > t2
  results > get(2) > t3

  println("   Task 1 result: {0}", t1)
  println("   Task 2 result: {0}", t2)
  println("   Task 3 result: {0}", t3)
  println("")

  return()
}(int)

// Example 4: Limited concurrency with worker pool
fn example_parallel_limited() {
  println("4. Parallel Limited (Worker Pool)")
  println("   Processing with max 2 concurrent operations...")

  // Create array of 10 items but only process 2 at a time
  parallel_limited(2, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (x int) {
    x > mul(2) > result
    return({}, result)
  }(map, int)) > result_tuple

  result_tuple > get(1) > results

  results > len() > count

  println("   Processed {0} items", count)
  println("   Results: {0}", results)
  println("")

  return()
}(int)

// Example 5: Race pattern - first to complete wins
fn example_parallel_race() {
  println("5. Parallel Race (First to Complete)")
  println("   Racing multiple operations...")

  [
    (dummy int) {
      42 > result
      return({}, result)
    }(map, int),
    (dummy int) {
      100 > result
      return({}, result)
    }(map, int),
    (dummy int) {
      7 > result
      return({}, result)
    }(map, int)
  ] > parallel_race() > result_tuple

  result_tuple > get(1) > winner

  println("   First result: {0}", winner)
  println("")

  return()
}(int)

// Example 6: Strict mode - fail fast
fn example_parallel_strict() {
  println("6. Parallel Strict (Fail-Fast)")

  // First try: all succeed
  println("   Try 1: All operations succeed...")
  [1, 2, 3] > parallel_strict((x int) {
    x > mul(2) > result
    return({}, result)
  }(map, int)) > result_tuple1

  result_tuple1 > get(0) > err1
  result_tuple1 > get(1) > results1

  err1 > absent?() > eq?(true) > (no_error bool) {
    no_error > return?("   Success!")
    return("   Failed (unexpected)")
  }(string) > msg1
  msg1 > println()
  println("   Results: {0}", results1)

  // Second try: one fails
  println("   Try 2: One operation fails...")
  [1, 2, 3, 4, 5] > parallel_strict((x int) {
    x > eq?(3) > is_three
    is_three > (cond bool) {
      err("Failed on 3") > e
      cond > return?(e, 0)
      return({}, x)
    }(map, int)
  }(map, int)) > result_tuple2

  result_tuple2 > get(1) > results2

  results2 > len() > eq?(0) > (is_empty bool) {
    is_empty > return?("   Failed fast as expected (results empty)")
    return("   Unexpected: got results")
  }(string) > msg2
  msg2 > println()

  println("")

  return()
}(int)

main()