# How the Result Package Represents Tuples for Operation Outcomes in Go

> Learn how the Go result package models operation outcomes using generic tuples with the Result[T] struct, offering type-safe error and value encapsulation for clearer code.

- Repository: [Aperture Robotics/util](https://github.com/aperturerobotics/util)
- Tags: deep-dive
- Published: 2026-02-25

---

**The `result` package models operation outcomes as generic tuples containing a value and an error using the `Result[T]` struct, which encapsulates both components in a single type-safe container.**

The `aperturerobotics/util` repository provides a lightweight solution for handling function returns in Go through its `result` package. This package eliminates the need for multiple return values by representing operation outcomes as structured tuples, making it easier to pass results between functions and store them in collections.

## Understanding the Result[T] Struct

At the core of the tuple representation is the generic `Result[T]` struct defined in [`result/result.go`](https://github.com/aperturerobotics/util/blob/main/result/result.go). This struct stores the successful return value alongside any error that occurred during execution:

```go
type Result[T comparable] struct {
    val T      // the operation's value
    err error  // the operation's error
}

```

The struct uses Go generics to constrain the value type `T` to `comparable`, ensuring that values can be equality-checked. This design allows the package to work with primitive types, strings, and other comparable structs while maintaining compile-time type safety.

## Constructing Result Tuples

The `NewResult` function creates tuple instances in a single call, accepting both the value and error as parameters:

```go
func NewResult[T comparable](val T, err error) *Result[T] {
    return &Result[T]{val: val, err: err}
}

```

This constructor pattern ensures that both components of the tuple are initialized simultaneously, preventing partial result states. By returning a pointer to the struct, the function enables efficient passing of results without copying the underlying data.

## Accessing and Comparing Results

The package provides methods to interact with the tuple components while preserving the value-error relationship. The `GetValue` method returns both elements in their original order:

```go
func (r *Result[T]) GetValue() (val T, err error) {
    return r.val, r.err
}

```

For validation purposes, the `Compare` method checks exact equality between two result tuples:

```go
func (r *Result[T]) Compare(ot *Result[T]) bool {
    return r.val == ot.val && r.err == ot.err
}

```

This comparison evaluates both the value and error fields, making it useful for unit testing and result caching scenarios.

## Practical Implementation Example

The following example demonstrates how to use the result package to represent operation outcomes in a real-world scenario:

```go
package main

import (
    "errors"
    "fmt"

    "github.com/aperturerobotics/util/result"
)

// Example operation that returns an int and an error.
func compute(x int) *result.Result[int] {
    if x < 0 {
        return result.NewResult[int](0, errors.New("negative input"))
    }
    return result.NewResult[int](x*x, nil)
}

func main() {
    r1 := compute(5)
    val, err := r1.GetValue()
    fmt.Printf("Result: %d, Err: %v\n", val, err) // Result: 25, Err: <nil>

    r2 := compute(-3)
    _, err = r2.GetValue()
    fmt.Printf("Error: %v\n", err) // Error: negative input

    // Comparing two results
    r3 := result.NewResult[int](25, nil)
    fmt.Println("Equal?", r1.Compare(r3)) // Equal? true
}

```

This implementation shows how the tuple representation simplifies error handling by encapsulating both success and failure states in a single returnable object.

## Summary

- The `result` package uses a generic `Result[T]` struct to represent operation outcomes as value-error tuples in [`result/result.go`](https://github.com/aperturerobotics/util/blob/main/result/result.go).
- **Construction** occurs through `NewResult`, which accepts both the value and error in a single call.
- **Access** methods like `GetValue` preserve the tuple structure while allowing destructuring into separate variables.
- **Comparison** via `Compare` enables equality checks against other result instances for testing and validation.
- The generic constraint on `T` ensures type safety while supporting any comparable Go type.

## Frequently Asked Questions

### How does the Result type differ from Go's native multiple return values?

While Go functions typically return values and errors as separate entities `(val, err)`, the `Result[T]` struct encapsulates both into a single object that can be stored in variables, passed to channels, or inserted into collections. This representation treats the outcome as a cohesive unit rather than separate return values, making it ideal for functional programming patterns and asynchronous operations.

### What types can be used with the Result generic parameter?

The `Result[T]` struct constrains `T` to the `comparable` interface, meaning any type that supports the `==` and `!=` operators. This includes primitive types like `int`, `string`, and `bool`, as well as arrays and structs composed of comparable types. Non-comparable types such as slices, maps, and functions cannot be used directly as the value type in a `Result`.

### When should I use Compare versus direct field access?

Use the `Compare` method when you need to verify that two operations produced identical outcomes, particularly in unit tests or caching scenarios where semantic equality matters. Direct field access through `GetValue` is preferred when you need to handle the value and error separately with custom logic, such as logging specific error types while processing successful values differently.