Proposal: try function constructor

106 views
Skip to first unread message

Li

unread,
Jun 28, 2019, 10:49:55 PM6/28/19
to golang-nuts
I propose a addition to current try proposal to enable optional error wrapping.

demo codes:

package main

import (
"fmt"
"io"
"os"
)

// wrapErr is an error wrapping function
func wrapErr(err error, format string, args ...interface{}) error {
return fmt.Errorf(
"%s: %s",
fmt.Sprintf(format, args...),
err.Error(),
)
// or other error implementation
}

// like the proposed try function but with custom wrapper
var try = makeTry(wrapErr)

// use like the proposed try with extra wrapping arguments
func CopyFile(src, dest string) (err error) {
r := try(os.Open(src), "open %s", src)
// if there is an error, it will be "open <src>: <err>" as returned by wrapErr
defer r.Close()
w := try(os.Create(dest), "create %s", dest)
defer func() {
w.Close()
if err != nil {
os.Remove(dest)
}
}()
try(io.Copy(w, r)) // bare try without arguments, so no wrapping
try(w.Close())
return nil
}


Actually I have implemented this by abusing panic/recover. 

I've been using this for a while. It works well to serve its purpose although bring in a little more overhead of panic/recover.

Denis Cheremisov

unread,
Jun 29, 2019, 3:22:41 PM6/29/19
to golang-nuts
Pooof

Are you serious?

Li

unread,
Jun 29, 2019, 8:14:30 PM6/29/19
to golang-nuts
Here's another demo that annotate errors with custom type.

package main

import (
"fmt"
"io"
"os"
)

type Err struct {
Code    string
Message string
Cause   error
}

var _ error = Err{}

func (e Err) Error() string {
return fmt.Sprintf("[%s] %s: %s", e.Code, e.Message, e.Cause.Error())
}

// wrapErr annotates an error with code and message
func wrapErr(err error, code string, message string, args ...interface{}) error {
return Err{
Code:    code,
Message: fmt.Sprintf(message, args...),
Cause:   err,
}
}

// like the proposed try function but with custom wrapper
var try = makeTry(wrapErr)

// use like the proposed try with extra wrapping arguments
func CopyFile(src, dest string) (err error) {
r := try(os.Open(src), "Open", "open %s", src)
defer r.Close()
w := try(os.Create(dest), "Create", "create %s", dest)
Reply all
Reply to author
Forward
0 new messages