Error Handling in GoloScript

Complete guide to error handling in GoloScript: exceptions, Result types, Option types, and functional approaches.

Introduction

GoloScript offers three complementary approaches to handle errors:

  1. Exceptions: For critical and unexpected errors
  2. Result Type: For operations that can fail predictably (Go/Rust style)
  3. Option Type: For values that may be absent (Rust/Haskell style)

These approaches can be combined to create robust and expressive code.

β˜… Insight ─────────────────────────────────────
Error Handling Philosophy: GoloScript adopts a pragmatic approach by combining traditional exceptions for exceptional errors with Result/Option types for expected cases. This combination provides both type safety and functional programming flexibility.

Errors as Values: The Result type allows treating errors as normal values, facilitating operation composition and avoiding issues with silent exceptions. This approach makes the error flow explicit in code.
─────────────────────────────────────────────────

Three Error Handling Approaches

Overview

Approach Usage Advantages Disadvantages
Exceptions Critical errors Guaranteed cleanup (finally) Can be ignored
Result Predictable operations Explicit, composable Sometimes verbose
Option Absent values Simple, type-safe No error message

Exceptions (try/catch/finally)

Basic Syntax

try {
  # Code that can throw an exception
  throw raise("Something went wrong")
} catch (e) {
  # Handle error
  println("Error:", e: message())
} finally {
  # Guaranteed cleanup (always executed)
  println("Cleanup")
}

When to Use

βœ“ Use for:

βœ— Avoid for:

Features

# Throw any value
throw "Error message"
throw 404
throw raise("Exception object")

# Try/finally (without catch)
try {
  # Code
} finally {
  # Cleanup always executed
}

# Re-throw an exception
catch (e) {
  # Logging
  throw e  # Propagate error
}

Result Type (Errors as Values)

Concept

The Result type represents either success (Ok) or error (Err). It’s a union type with two variants:

union ResultType = {
  Ok = { value },
  Err = { message }
}

Creation

import gololang.Errors

# Create success
let success = Result(42)        # or Ok(42)

# Create error
let failure = Error("Failed")   # or Err("Failed")

Type Checking

# With methods
if result: isOk() {
  let value = result: value()
}

if result: isError() {
  let msg = result: message()
}

# With functions
if isOk(result) { ... }
if isError(result) { ... }

Pattern Matching with either

either(result,
  |value| -> println("Success:", value),
  |error| -> println("Error:", error)
)

Transformations

# mapResult: transform value if Ok
let doubled = mapResult(result, |x| -> x * 2)

# flatMapResult: chain operations
let result = flatMapResult(parseInt("42"), |num| {
  return safeDivide(num, 2)
})

# orElse: default value
let value = orElse(result, 0)

Complete Example

function safeDivide = |a, b| {
  if b == 0 {
    return Error("Division by zero")
  }
  return Result(a / b)
}

function safeSquareRoot = |x| {
  if x < 0 {
    return Error("Negative number")
  }
  return Result(x)  # Simplified sqrt
}

# Pipeline
let result = flatMapResult(safeDivide(100, 4), |quotient| {
  return safeSquareRoot(quotient)
})

either(result,
  |value| -> println("Result:", value),
  |error| -> println("Error:", error)
)

Option Type (Nullable Values)

Concept

The Option type represents either a present value (Some) or absence (None):

union Option = {
  Some = { value },
  None
}

Creation

import gololang.Errors

# Present value
let present = some(42)

# Absent value
let absent = none()

Checking

if opt: isSome() {
  let value = unwrap(opt)
}

if opt: isNone() {
  println("No value")
}

Operations

# getOrElse: default value
let value = getOrElse(opt, 999)

# mapOption: transform if present
let doubled = mapOption(opt, |x| -> x * 2)

# flatMapOption: chain
let result = flatMapOption(opt, |x| {
  if x > 0 {
    return some(x * 2)
  }
  return none()
})

# filter: filter by predicate
let filtered = filter(opt, |x| -> x > 10)

Conversions

# Option -> Result
let result = toResult(option)  # None becomes Error("Empty option")

# Result -> Option
let option = toOption(result)  # Error becomes None

When to Use Each Approach

Decision Matrix

Situation                          β†’ Recommended Approach
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
User input parsing                 β†’ Result
File reading                       β†’ Result
Form validation                    β†’ Result
Division by zero                   β†’ Result

Collection search                  β†’ Option
Optional configuration             β†’ Option
Nullable value                     β†’ Option

Out of memory                      β†’ Exception
Invariant violation                β†’ Exception
Data corruption                    β†’ Exception
System resource unavailable        β†’ Exception

Choice Guide

Use Result when:

Use Option when:

Use Exception when:

gololang.Errors Module

Creation Functions

Function Description Returns
Result(value) Create success ResultType.Ok
Error(message) Create error ResultType.Err
Ok(value) Alias for Result ResultType.Ok
some(value) Create present Option Option.Some
none() Create absent Option Option.None

Result Functions

Function Description
isOk(result) Check if Ok
isError(result) Check if Error
either(result, okFn, errFn) Pattern matching
mapResult(result, fn) Transform value
flatMapResult(result, fn) Chain Results
orElse(result, default) Default value
andThen(result, fn) Composition

Option Functions

Function Description
isSome(opt) Check if Some
isNone(opt) Check if None
unwrap(opt) Extract value
getOrElse(opt, default) Default value
mapOption(opt, fn) Transform if present
flatMapOption(opt, fn) Chain Options
filter(opt, predicate) Filter

Conversions

Function Description
toResult(option) Option β†’ Result
toOption(result) Result β†’ Option
trying(block) Exception β†’ Result

Parsing

Function Description Type
parseInt(str) Parse integer Result[Int, String]
parseFloat(str) Parse float Result[Float, String]

Examples

Example 1: Form Validation

import gololang.Errors

function validateEmail = |email| {
  if email: isEmpty() {
    return Error("Email cannot be empty")
  }
  if not email: contains("@") {
    return Error("Email must contain @")
  }
  return Result(email)
}

function validateAge = |ageStr| {
  return flatMapResult(parseInt(ageStr), |age| {
    if age < 18 {
      return Error("Must be 18 or older")
    }
    return Result(age)
  })
}

function registerUser = |email, ageStr| {
  return flatMapResult(validateEmail(email), |validEmail| {
    return flatMapResult(validateAge(ageStr), |validAge| {
      return Result("User registered: " + validEmail)
    })
  })
}

# Usage
either(registerUser("alice@example.com", "25"),
  |msg| -> println("βœ“", msg),
  |err| -> println("βœ—", err)
)

Example 2: Transformation Pipeline

# Parse -> Validate -> Transform
function processNumber = |numStr| {
  return flatMapResult(parseInt(numStr), |num| {
    if num <= 0 {
      return Error("Must be positive")
    }
    return Result(num * 2)
  })
}

# Usage with multiple values
let inputs = array("10", "abc", "-5", "20")

foreach input in inputs {
  either(processNumber(input),
    |result| -> println("βœ“", input, "->", result),
    |error| -> println("βœ—", input, "->", error)
  )
}

Example 3: Option for Search

function findInArray = |arr, target| {
  var idx = 0
  foreach item in arr {
    if item == target {
      return some(idx)
    }
    idx = idx + 1
  }
  return none()
}

# Usage
let numbers = array(10, 20, 30)

let result = findInArray(numbers, 20)
if result: isSome() {
  println("Found at index", unwrap(result))
} else {
  println("Not found")
}

Example 4: Combining Result and Option

function parseAndFind = |numStr, arr| {
  # Parse returns Result
  return flatMapResult(parseInt(numStr), |num| {
    # findInArray returns Option
    let opt = findInArray(arr, num)
    # Convert Option to Result
    return toResult(opt)
  })
}

# Usage
either(parseAndFind("20", array(10, 20, 30)),
  |idx| -> println("Found at index", idx),
  |err| -> println("Error:", err)
)

Example 5: Exceptions for Cleanup

try {
  # Open resource
  println("Opening resource...")

  # Operation that can fail
  throw raise("Operation failed")

} catch (e) {
  println("Error:", e: message())
} finally {
  # Cleanup always executed
  println("Closing resource...")
}

Note: This guide covers GoloScript’s error handling features. For more information on union types used by Result and Option, see the unions documentation.

Β© 2026 GoloScript Project | Built with Gu10berg

Subscribe: πŸ“‘ RSS | βš›οΈ Atom