< up >
2024-12-03

go yolo

tl;dr Go generics can be used to drop the error of two-return-value functions to enable chaining functions quickly:

func Yolo[T any](value T, _ error) T {
  return value
}

func main(){
  // Atoi has signature func(s string) (int, error)
  fmt.Println(Yolo(strconv.Atoi("21")) + Yolo(strconv.Atoi("21")))
  // 42
}

Content

AoC error handling

It’s advent of code time again! My utility lib stellar is growing with generators.

One thing bugged me over the years: error handling. In this post I want to show you my Yolo function that consumes any error of a function with only one other value.

Error handling

Error handling is extremely important for writing reliable and maintainable code. Once I started over with C, checking errno as often as possible saved me a load of time debugging.

On the other hand, error handling is time consuming when assumptions can be made. Like converting the aoc input consisting only of numbers.

No error handling

In Golang, errors get returned and need to be handled explicitly. They can be ignored via “_” in an assignment, but by default it can’t be left on chaining functions like this:

func AnswerOfLife(a int) (int, error){
  if a == 42{
    return 42, nil
  }  
  return -1, errors.New("The answer to the ultimate question of life, the universe, and everything not found")
}

func main(){
  fmt.Println(AnswerOfLife(42) + AnswerOfLife(1337))
}

This doesn’t work, as AnswerOfLife has multiple return values: multiple-value AnswerOfLife(42) (value of type (int, error)) in single-value context.

Yolo

You only life once is my answer to this problem:

func Yolo[T any](value T, _ error) T {
	return value
}

It takes the result of a function with two return values and drops the error.

This doesn’t come without a prize. Our code compiles but due to the missing error handling, the result may be confusing. Our program now compiles and outputs 41.

This is really bad for debugging. Therefore I created some variants that handle the error differently, depending on the situation:

func YoloBoom[T any](value T, err error) T {
	if err != nil {
		panic(err.Error())
	}
	return value
}

func YoloDefault[T any](value T, err error) T {
	if err == nil {
		return value
	}
	var def T
	return def
}

The first panics on error right away for situations where errors are unlikely. The second returns the default value of the value’s type. The later is useful when erroneous function calls should not be considered in an addition as YoloDefault would just return zero.