Orthogonality: how does this change interact or overlap with existing features? - complements existing.
Is the goal of this change a performance improvement? - for developers.
What quantifiable improvement should we expect? - Reduce work with errors only to determine the place of their processing.
Does this affect error handling? - Yes.
How does this differ from previous error handling proposals? - complements the existing implementation of functions.
Is this about generics? - No.
In "What to avoid":
Other languages have not it.
My proposal states a idea rather than a solution.
All functions can be return Error by default.
Its mean that all functions always return error = nil and if catch, than error != nil.
In the place where error handling is required, then call the handling function (handling() or ifError() or checkError() or someNameFunctionErrorHandling() and etc.), here let it be checkError().
func anyFunc() error {var err error; return err} == func anyFunc() {}
so then
main()
|
˅
func() // if need error processing - "Any Error"
| ^
˅ |
func() // default forwarding error
| ^
˅ |
func() // getting an error - "Any Error"
Please see examples for understanding.
Old
func doAny() (int, error) { if true{ // simulate getting an error return 0, Errors.New("Any Error") } return 1, nil } main() { _, err := doAny() if err != nil { // error processing fmt.Println(err) // "Any Error" } }
New (at first glance, in the simple case, almost nothing has changed)
func doAny() int { if true{ // simulate getting an error return Errors.New("Any Error"), 0 // allways error is the first returned value } return 1 } main() { i := doAny() checkError() { // error processing fmt.Println(err) // "Any Error" } }
Old
func doAny() (int, error) { if true{ // simulate getting an error return 0, Errors.New("First Error") } return 1, nil } main() { defer func() { if err != nil { // last error processing fmt.Println(err) // "Second Error" } }() _, err := doAny() if err != nil { // current error processing from doAny() fmt.Println(err) // "First Error" err = Errors.New("Second Error") } }
New (we are able to immediately process the first error encountered)
func doAny() int { if true{ // simulate getting an error return Errors.New("First Error"), 0 } return 1 } main() { checkError() { // first error processing fmt.Println(err) // "First Error" } defer checkError() { // last error processing fmt.Println(err) // "Second Error" } i := doAny() checkError() { // current error processing from doAny() fmt.Println(err) // "First Error" } err = Errors.New("Second Error") }
Old
func doAny() (int, error) { if true{ // simulate getting an error return 0, Errors.New("Any Error") } return 1, nil } func doNext() error { ... _, err := doAny() if err != nil { return err } return nil } main() { err := doNext() if err != nil { // error processing fmt.Println(err) // "Any Error" } }
New (we can forget to forward the error, but not here)
func doAny() int { if true{ // simulate getting an error return Errors.New("Any Error"), 0 } return 1 } func doNext() { ... doAny() } // just forwarding last error main() { _ = doNext() checkError() { // error processing fmt.Println(err) // "Any Error" err = nil // and can forwarding nil as error } }
Thank you.