Categorygithub.com/mitranim/try
modulepackage
0.1.5
Repository: https://github.com/mitranim/try.git
Documentation: pkg.go.dev

# README

Overview

Shorter error handling for Go. Supports two approaches:

Features:

  • Uses a combination of defer and panics to make code significantly shorter, at an acceptable runtime cost.
  • Automatically ensures stacktraces via "github.com/pkg/errors".
  • You can choose to keep error in signatures and use explicit "try".
  • You can choose to drop error from signatures and use exceptions.

See API docs at https://pkg.go.dev/github.com/mitranim/try.

TOC

Why

Go wants you to add meaningful context when handling errors. I sympathize with this idea, and do it often. But there's code where annotating every single failure is not practical and/or bloats the code beyond our ability to read it back.

func someFuncA() error {
  err := someFuncB()
  if err != nil {
    return errors.WithMessage(err, `failed to X`)
  }
  err = someFuncC()
  if err != nil {
    return errors.WithMessage(err, `failed to X`)
  }
  err = someFuncD()
  if err != nil {
    return errors.WithMessage(err, `failed to X`)
  }
  return nil
}

Using the "try" style:

func someFuncA() (err error) {
  defer try.RecWithMessage(&err, `failed to X`)
  try.To(someFuncB())
  try.To(someFuncC())
  try.To(someFuncD())
  return
}

Using the "exceptions" style:

func someFuncA() {
  defer try.Detail(`failed to X`)
  someFuncB()
  someFuncC()
  someFuncD()
}

The code should speak for itself. This won't be usable for every codebase, see Limitations below, but can be a nice improvement for some.

Limitations

This has a minor runtime cost. Use this for IO-heavy control code, where the cost is barely measurable. Avoid this in CPU-heavy code or libraries.

This package provides a variety of "try" functions for common cases, but it can't define something generic like the original proposal did. To make your code compatible, prefer to use pointers for "inout" parameters of non-primitive types, and return only error:

func someFunc(input A, out *B) error {
  *out = someOperation(input)
  return someErr
}

var val B
try.To(someFunc(input, &val))

...Or use inout parameters and panics:

func someFunc(input A, out *B) {
  *out = someOperation(input)
}

var val B
someFunc(input, &val)

In the current state of Go, functions conforming to this pattern are easier to compose, leading to much shorter code.

Naming

The term "must" is more conventional in the Go standard library, but this library uses "try" because it's more grammatically flexible: "try string" works, but "must string" would not. The "try" proposal used "try". Swift error handling is very similar and uses "try". (Unlike Swift, we have stacktraces.)

Changelog

v0.1.5

Breaking renaming for consistency:

  • IgnoreIgnoreOnly
  • IgnoringIgnoringOnly
  • WithTransTransing

Added:

  • Ignore
  • Ignoring

v0.1.4

Breaking: renamed Caught to CaughtOnly for consistency, added Caught.

v0.1.3

Added DetailOnly and DetailOnlyf.

v0.1.2

Added tools to support the "exceptions" style. For many apps, it's a better fit than either the Go style or the "try" style.

License

https://unlicense.org

Misc

I'm receptive to suggestions. If this library almost satisfies you but needs changes, open an issue or chat me up. Contacts: https://mitranim.com/#contacts

# Functions

A "try" function that takes and returns a value of type `bool`.
A "try" function that takes and returns a value of type `[]bool`.
A "try" function that takes and returns a value of type `byte`.
A "try" function that takes and returns a value of type `[]byte`.
Converts a panic to an error, idempotently adding a stacktrace.
Converts a panic to an error, if the error satisfies the provided test.
Shortcut for `Catch() != nil`.
Shortcut for `CatchOnly() != nil`.
A "try" function that takes and returns a value of type `complex128`.
A "try" function that takes and returns a value of type `[]complex128`.
A "try" function that takes and returns a value of type `complex64`.
A "try" function that takes and returns a value of type `[]complex64`.
Must be deferred.
Must be deferred.
Must be deferred.
Must be deferred.
Converts an arbitrary value to an error.
Must be deferred.
A "try" function that takes and returns a value of type `float32`.
A "try" function that takes and returns a value of type `[]float32`.
A "try" function that takes and returns a value of type `float64`.
A "try" function that takes and returns a value of type `[]float64`.
True if this error, or any of the errors it wraps, has a stacktrace provided by "github.com/pkg/errors".
Must be deferred.
Must be deferred.
Runs a function, catching and ignoring ALL panics.
Runs a function, catching and ignoring only the panics that satisfy the provided test.
A "try" function that takes and returns a value of type `int`.
A "try" function that takes and returns a value of type `int16`.
A "try" function that takes and returns a value of type `[]int16`.
A "try" function that takes and returns a value of type `int32`.
A "try" function that takes and returns a value of type `[]int32`.
A "try" function that takes and returns a value of type `int64`.
A "try" function that takes and returns a value of type `[]int64`.
A "try" function that takes and returns a value of type `int8`.
A "try" function that takes and returns a value of type `[]int8`.
A "try" function that takes and returns a value of type `interface{} value.
A "try" function that takes and returns a value of type `[]interface{}`.
A "try" function that takes and returns a value of type `[]int`.
Must be deferred.
Must be deferred.
Must be deferred.
Must be deferred.
Must be deferred.
Must be deferred.
Must be deferred.
A "try" function that takes and returns a value of type `rune`.
A "try" function that takes and returns a value of type `[]rune`.
A "try" function that takes and returns a value of type `string`.
A "try" function that takes and returns a value of type `[]string`.
Simplifies control flow by panicking on non-nil errors.
Must be deferred.
Must be deferred.
Runs a function, "transmuting" the resulting panics by calling the provided transformer, which may choose to suppress or wrap specific error types.
A "try" function that takes and returns a value of type `uint`.
A "try" function that takes and returns a value of type `uint16`.
A "try" function that takes and returns a value of type `[]uint16`.
A "try" function that takes and returns a value of type `uint32`.
A "try" function that takes and returns a value of type `[]uint32`.
A "try" function that takes and returns a value of type `uint64`.
A "try" function that takes and returns a value of type `[]uint64`.
A "try" function that takes and returns a value of type `uint8`.
A "try" function that takes and returns a value of type `[]uint8`.
A "try" function that takes and returns a value of type `uintptr`.
A "try" function that takes and returns a value of type `[]uintptr`.
A "try" function that takes and returns a value of type `[]uint`.
Must be deferred.
Must be deferred.
Adds a stacktrace via "github.com/pkg/errors", unless the error already has one.

# Structs

Used by `Err()` to wrap non-errors received from `recover()` and convert them to errors.