Skip to content

Proposal: Go 2: error handling by assignment, with named handlers #32500

Closed
@networkimprov

Description

@networkimprov

Background

The feedback wiki for the Go 2 Draft Design proposing check/handle saw the emergence of two recurring themes, documented here:
https://github.com/golang/go/wiki/Go2ErrorHandlingFeedback#recurring-themes

13 responses suggested a nil test triggered by assignment, to reduce if err != nil boilerplate:

f, ? := os.Open(...) // one of many syntaxes suggested

17 responses suggested named error handlers, to enable multiple error paths within a function:

func example(c net.Conn) error {
   a := check os.Open(...) ? openErr // one of many syntaxes suggested
   ...
   b := check os.Open(...) ? openErr
   ...
   check io.Copy(c, a) ? copyErr
   check io.Copy(c, b) ? copyErr
   ...
   handle openErr { ... } // log error
   handle copyErr { ... } // log error, write error msg to c
   return nil
}

Others have newly reiterated both themes in comments on the try() proposal #32437.

Herein is a composite of these recurring themes. I believe it bears consideration in light of the apparently deep resistance to try().

Summary

v, flag [op] := f()

try v, flag [op] := f() // alternative, to indicate control-flow within statement

  • flag indicates that a zero-value test shall be performed on that return value,
  • op gives an optional procedure to invoke on a non-zero value,
    e.g. return, panic, or a named handler (defined at package-level or in current function)
  • try is a new keyword
  • v is an ordinary variable
  • := is any declaration or assignment operator
  • func f() (int, error)

Possible syntax (choose one)

   f, #return  := os.Open(...)
   f, ?return  := os.Open(...)
   f, @return  := os.Open(...)
   f, {return} := os.Open(...)

   try f, #  := os.Open(...)
   try f, ?  := os.Open(...)
   try f, @  := os.Open(...)
   try f, {} := os.Open(...)

Possible ops

   f, #return := os.Open(...)
   f, #panic  := os.Open(...)
   f, #hname  := os.Open(...) // invoke user-defined handler
   f, #       := os.Open(...) // ignore, or invoke "ignored" handler if defined

   try f, #      := os.Open(...) // return
   try f, #panic := os.Open(...)
   try f, #hname := os.Open(...)
   try f, #_     := os.Open(...) // ignore

Example handlers

   handle fatal (err error) {
      debug.PrintStack()
      log.Fatal(err)
   }

   handle log (err error, clr caller) { 
      fmt.Fprintf(os.Stderr, "%s got %s, continuing\n", clr.name, err)
      // may return the parent function or not, to support recoverable errors
   }
   // caller is a handle-specific type with results of runtime.Caller()

A sub-expression syntax (which has caused complaint in the try() comments) is possible, but only recommended for ignore or panic ops:

f(os.Open#(...))       // ignore
f(os.Open#panic(...))
f(os.Open#p(...))      // any leading substring of panic?

f(#      os.Open(...)) // prefix alternative
f(#panic os.Open(...))

f(os.Open(...) #)      // postfix alternative
f(os.Open(...) #panic)

About that Pesky New Symbol

People seem to dislike #op or @op or ?op, so let's ponder an alternative.

We could define three new keywords (for ops return, panic, invoke). They constrain the return value tested to the last one. To date, try & must have been suggested for return & panic, and we could employ check for invoke. One can already use _ for op ignore, although it looks like a bug, and blank-assigned values can't be logged for debugging.

try   f := os.Open(...)            // return

must  f := os.Open(...)            // panic

check f := os.Open(...) else hname // invoke hname

   f, _ := os.Open(...)            // wait, is that a bug?

I'd rather define one new keyword (or none) and see a symbol with an op that names its action.

Work in Progress

As the try() proposal may be adopted, I leave this proposal in an incomplete state. I may develop it further if the Go team expresses interest.

More possibilities are described in Requirements to Consider for Go 2 Error Handling, but most of them are not "recurring themes".

Who's @networkimprov? Liam is the author of

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeLanguageChangeSuggested changes to the Go languageProposalerror-handlingLanguage & library change proposals that are about error handling.v2An incompatible library change

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions