https://seankhliao.com/blog/12020-11-23-go-error-handling-proposals/ blog 12020-11-23 SEAN K.H. LIAO error handling if err != nil { // handle error } Error handling seems to be a recurring theme in go, but most proposals get nowhere. * Go2ErrorHandlingFeedback * label:error-handling proposals baseline code x, err := foo() if err != nil { return nil, wrap(err) } handling note: almost all the ones that claim to use "plain functions" as error handlers have an implicit nonlocal return predeclared handlers * handle err { return _, wrap(err) } x := check foo(): block scoped * handle err { return _, wrap(err) } x, # := foo() * handle func(err error) (T, error) { return _, wrap(err) } x, ? := foo() * watch err { if err != nil { return _, wrap(err) } } x, err != foo() * expect err != nil { return _, wrap(err) } x, err := foo() * with { return _, wrap(err) } handle err { x, err := foo() } call specific handler * x, #err := foo() catch err { return _, wrap(err) }: tagged error handlers * x, @err := foo() err: return _, wrap(err): goto label * grab err() { if err != nil { return _, wrap(err) } } x, err() := foo(): assign to handler * err := inline(err error){ if err != nil { return _, wrap(err) } } x, err := foo(): assign to handler * err := func(err error) (T, error) { return _, wrap(err) } x, #err := foo(): block scoped * _check = func(err error) (T, error) { return _, wrap(err)} x, ?err := foo(): not fully formed idea on return * handler := func(err error) (T, error) { return^2 _, wrap(err) } x, handler(err) := foo(): note nonlocal return wrapping some rely on wrap being smart and passing through nil (so not fmt.Errorf), * x, err := foo() reflow _, wrap(err): implicit err != nil and return * x, err := foo() refuse _, wrap(err) * x, err := foo() pass _, wrap(err) * x, err := foo() ereturn _, wrap(err) * x, err := foo() err ?: return _, wrap(err) * x, err := foo() on err, return _, wrap(err) * x, err := foo() err ? { return _, wrap(err) } * x, err := foo() onErr { return _, wrap(err) } * x, err := foo() if err != nil { return _, wrap(err) }, also: if ... on 1 line * x, err := foo() if !err { return _, wrap(err) } * x, err := foo() if err { return _, wrap(err) } * x, err := foo() if err? { return _, wrap(err) } * x, err := foo(); if err != nil { return _, wrap(err) }, also: everything on 1 line * x, err := foo() /* err */ { return _, wrap(err) }, also * x, err := foo() ?? { return _, wrap(err) } * x, err := foo(); err.return wrap(err) * x := foo() or err: return _, wrap(err) * x := foo() ?err return _, wrap(err) * x := check wrap() foo(), also * x := foo() ? wrap() * x := foo() or wrap() * x := foo() || wrap(err) * x := foo() on_error err fail wrap(err) * x := foo() onerr return _, wrap(err) * x := try(foo(), wrap) * x := collect(&err, foo(), wrap) * try x, err := foo() { return _, wrap(err) } return can use defer for wrapping * x := try(foo()) * x := must(foo()): panic instead of return * x := foo!() * x := foo()?, also * x := #foo() * x := guard foo() * x := must foo() * x, # := foo(): panic instead of return * x, ? := foo(), also * x, ! := foo(), also, panic * x, !! := foo() * x, !err := foo() * x, ^err := foo() * x, err? := foo() * x, err := foo() throws err * tryfunc func(...){ x := foo() } * x, err := foo() check(err): builtin if err != nil { return ..., err } macro * x, err := foo() catch(err): builtin if err != nil { return ..., err } macro try..catch * try { x := foo() } catch(e Exception) { ??? }: literally try catch * try err != nil { x, err := foo() } except { return _, wrap(err) } * until err != nil { check x, err := foo() } else { return _, wrap (err) }: insert after every check * break err != nil { step: x, err := foo() }: insert after every repeatable label * break err != nil { try x, err := foo() }: insert after every try * if x, err := foo(); err != nil { return _, wrap(err) } else { ... } undo { ??? } done { ??? } defer { ??? } * handler := func(err error) error { return wrap(err) } check(handler){ x := foo() } * check { x := check foo() } handle err { return _, wrap(err) } * check { x, err1 := foo() } catch err { return _, wrap(err) } * check { x, err := foo() catch: return _, wrap(err) } * x, err := foo() !!! fail: return _, wrap(err): goto label * handle err { x, err := foo()
case err != nil: return _, wrap (err) } * try { x := foo(); if err != nil { return _, wrap(err) } } others * x, (err) := foo(): only assign to LHS if () content is not currently nil * collect err { x, _! := foo() } if err != nil { return _, wrap(err) }: err is an value that accumulates errors? does it continue? * errorhandling(err){ x, err := foo() }: err is an accumulator? messes with types * x, err := foo() handle err1 || err2 || err3 { return _, wrap(err) }: shorter if chain? * nonlocal return * nonlocal return with return type * returnfrom label, err: nonlocal return * result type: box of value|err allows passthrough home | blog | github