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:
- Exceptions: For critical and unexpected errors
- Result Type: For operations that can fail predictably (Go/Rust style)
- 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:
- Critical unexpected errors (out of memory, file system errors)
- Contract violations (preconditions, invariants)
- Situations requiring guaranteed cleanup (resource closure)
β Avoid for:
- Normal control flow
- Frequently failing operations
- User data validation
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:
- Operation can fail in a predictable way
- You need a descriptive error message
- You want to compose multiple operations (pipeline)
- Caller must explicitly handle the error
Use Option when:
- A value may simply be absent
- You donβt need to know why itβs absent
- Youβre doing a search that may find nothing
- You want to avoid
nullsafely
Use Exception when:
- Error is truly unexpected
- You need guaranteed cleanup (finally)
- Error indicates a bug in the program
- Propagating error through multiple layers
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