try

package module
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2022 License: BSD-3-Clause Imports: 2 Imported by: 56

README

Try: Simplified Error Handling in Go

GoDev Build Status

This module reduces the syntactic cost of error handling in Go.

Example usage in a main program:

func main() {
    defer try.F(log.Fatal)
    b := try.E1(os.ReadFile(...))
    var v any
    try.E(json.Unmarshal(b, &v))
    ...
}

Example usage in a unit test:

func Test(t *testing.T) {
    defer try.F(t.Fatal)
    db := try.E1(setdb.Open(...))
    defer db.Close()
    ...
    try.E(db.Commit())
}

Code before try:

func (a *MixedArray) UnmarshalNext(uo json.UnmarshalOptions, d *json.Decoder) error {
    switch t, err := d.ReadToken(); {
    case err != nil:
        return err
    case t.Kind() != '[':
        return fmt.Errorf("got %v, expecting array start", t.Kind())
    }

    if err := uo.UnmarshalNext(d, &a.Scalar); err != nil {
        return err
    }
    if err := uo.UnmarshalNext(d, &a.Slice); err != nil {
        return err
    }
    if err := uo.UnmarshalNext(d, &a.Map); err != nil {
        return err
    }

    switch t, err := d.ReadToken(); {
    case err != nil:
        return err
    case t.Kind() != ']':
        return fmt.Errorf("got %v, expecting array end", t.Kind())
    }
    return nil
}

Code after try:

func (a *MixedArray) UnmarshalNext(uo json.UnmarshalOptions, d *json.Decoder) (err error) {
    defer try.Handle(&err)
    if t := try.E1(d.ReadToken()); t.Kind() != '[' {
        return fmt.Errorf("found %v, expecting array start", t.Kind())
    }
    try.E(uo.UnmarshalNext(d, &a.Scalar))
    try.E(uo.UnmarshalNext(d, &a.Slice))
    try.E(uo.UnmarshalNext(d, &a.Map))
    if t := try.E1(d.ReadToken()); t.Kind() != ']' {
        return fmt.Errorf("found %v, expecting array end", t.Kind())
    }
    return nil
}

See the documentation for more information.

Install

go get -u github.com/dsnet/try

License

BSD - See LICENSE file

Documentation

Overview

Package try emulates aspects of the ill-fated "try" proposal using generics. See https://golang.org/issue/32437 for inspiration.

Example usage:

func Fizz(...) (..., err error) {
	defer try.HandleF(&err, func() {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
	})
	... := try.E2(Buzz(...))
	return ..., nil
}

This package is a sharp tool and should be used with care. Quick and easy error handling can occlude critical error handling logic. Panic handling generally should not cross package boundaries or be an explicit part of an API.

Package try is a good fit for short Go programs and unit tests where development speed is a greater priority than reliability. Since the E functions panic if an error is encountered, recovering in such programs is optional.

Code before try:

func (a *MixedArray) UnmarshalNext(uo json.UnmarshalOptions, d *json.Decoder) error {
	switch t, err := d.ReadToken(); {
	case err != nil:
		return err
	case t.Kind() != '[':
		return fmt.Errorf("got %v, expecting array start", t.Kind())
	}

	if err := uo.UnmarshalNext(d, &a.Scalar); err != nil {
		return err
	}
	if err := uo.UnmarshalNext(d, &a.Slice); err != nil {
		return err
	}
	if err := uo.UnmarshalNext(d, &a.Map); err != nil {
		return err
	}

	switch t, err := d.ReadToken(); {
	case err != nil:
		return err
	case t.Kind() != ']':
		return fmt.Errorf("got %v, expecting array end", t.Kind())
	}
	return nil
}

Code after try:

func (a *MixedArray) UnmarshalNext(uo json.UnmarshalOptions, d *json.Decoder) (err error) {
	defer try.Handle(&err)
	if t := try.E1(d.ReadToken()); t.Kind() != '[' {
		return fmt.Errorf("found %v, expecting array start", t.Kind())
	}
	try.E(uo.UnmarshalNext(d, &a.Scalar))
	try.E(uo.UnmarshalNext(d, &a.Slice))
	try.E(uo.UnmarshalNext(d, &a.Map))
	if t := try.E1(d.ReadToken()); t.Kind() != ']' {
		return fmt.Errorf("found %v, expecting array end", t.Kind())
	}
	return nil
}

Quick tour of the API

The E family of functions all remove a final error return, panicking if non-nil.

Handle recovers from that panic and allows assignment of the error to a return error value. Other panics are not recovered.

func f() (err error) {
	defer try.Handle(&err)
	...
}

HandleF is like Handle, but it calls a function after any such assignment.

func f() (err error) {
	defer try.HandleF(&err, func() {
		if err == io.EOF {
			err = io.ErrUnexpectedEOF
		}
	})
	...
}

func foo(i int) (err error) {
	defer try.HandleF(&err, func() {
		err = fmt.Errorf("unable to foo %d: %w", i, err)
	})
	...
}

F wraps an error with file and line information and calls a function on error. It inter-operates well with testing.TB and log.Fatal.

func TestFoo(t *testing.T) {
	defer try.F(t.Fatal)
	...
}

func main() {
	defer try.F(log.Fatal)
	...
}

Recover is like F, but it supports more complicated error handling by passing the error and runtime frame directly to a function.

 func f() {
 	defer try.Recover(func(err error, frame runtime.Frame) {
 		// do something useful with err and frame
	})
 	...
 }

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func E

func E(err error)

E panics if err is non-nil.

func E1

func E1[A any](a A, err error) A

E1 returns a as is. It panics if err is non-nil.

func E2

func E2[A, B any](a A, b B, err error) (A, B)

E2 returns a and b as is. It panics if err is non-nil.

func E3

func E3[A, B, C any](a A, b B, c C, err error) (A, B, C)

E3 returns a, b, and c as is. It panics if err is non-nil.

func E4

func E4[A, B, C, D any](a A, b B, c C, d D, err error) (A, B, C, D)

E4 returns a, b, c, and d as is. It panics if err is non-nil.

func F

func F(fn func(...any))

F recovers an error previously panicked with an E function, wraps it, and passes it to fn. The wrapping includes the file and line of the runtime frame in which it occurred. F pairs well with testing.TB.Fatal and log.Fatal.

func Handle

func Handle(errptr *error)

Handle recovers an error previously panicked with an E function and stores it into errptr.

func HandleF

func HandleF(errptr *error, fn func())

HandleF recovers an error previously panicked with an E function and stores it into errptr. If it recovers an error, it calls fn.

func Recover

func Recover(fn func(err error, frame runtime.Frame))

Recover recovers an error previously panicked with an E function. If it recovers an error, it calls fn with the error and the runtime frame in which it occurred.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL