From 750635bd1a9b5955fcf040dfe7ce8aedc77871da Mon Sep 17 00:00:00 2001 From: Theta-Dev Date: Sun, 27 Mar 2022 03:03:42 +0200 Subject: [PATCH] update to use generics --- README.md | 30 +---- embed.go | 11 -- go.mod | 2 +- gotry_generate/main.go | 150 --------------------- try/std_types.go | 290 ----------------------------------------- try/std_types_test.go | 68 ---------- try/try.go | 68 +++++----- try/try_test.go | 60 +++++---- try/types.csv | 29 ----- try/types.tmpl | 31 ----- 10 files changed, 63 insertions(+), 676 deletions(-) delete mode 100644 embed.go delete mode 100644 gotry_generate/main.go delete mode 100644 try/std_types.go delete mode 100644 try/std_types_test.go delete mode 100644 try/types.csv delete mode 100644 try/types.tmpl diff --git a/README.md b/README.md index 3012b47..b09d631 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,7 @@ # gotry This package is a fork of lainio's [err2](https://github.com/lainio/err2) -package with an improved code generator. - -## Add custom try package to your project - -``` -go install code.thetadev.de/ThetaDev/gotry/gotry_generate - -gotry_generate -init -``` - -### Add type definitions - -``` -📂 try/types.csv - -;;;;... - -# Example: -DB;*gorm.DB;gorm.io/gorm - -# Add +s to the method name to generate 2 handlers for single values and slices -String+s;string -``` - -### Generate - -```sh -go generate ./try -``` +package. ## Handle errors diff --git a/embed.go b/embed.go deleted file mode 100644 index 0d2fa71..0000000 --- a/embed.go +++ /dev/null @@ -1,11 +0,0 @@ -package gotry - -import "embed" - -//go:generate go run ./gotry_generate -of std_types - -//go:embed try/*.go -var TryFiles embed.FS - -//go:embed try/types.tmpl -var TypesTemplate string diff --git a/go.mod b/go.mod index 4297b63..8de9ba9 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module code.thetadev.de/ThetaDev/gotry -go 1.16 +go 1.18 diff --git a/gotry_generate/main.go b/gotry_generate/main.go deleted file mode 100644 index 6584b40..0000000 --- a/gotry_generate/main.go +++ /dev/null @@ -1,150 +0,0 @@ -package main - -import ( - "bufio" - "flag" - "fmt" - "os" - "os/exec" - "path" - "regexp" - "strings" - "text/template" - - "code.thetadev.de/ThetaDev/gotry" - "code.thetadev.de/ThetaDev/gotry/try" -) - -var variablePattern = regexp.MustCompile(`^(\w[\w\d]*)(\+s)?$`) - -type line struct { - Name string - WithSlice bool - Types []string - UseExt bool -} - -func parseDefinitions(defFileName, outFileName, pkgName string) (err try.Err) { - defer try.Annotate(&err, "error parsing definitions") - - defFile := try.File(os.Open(defFileName)) - useExt := pkgName != "try" - - fileScanner := bufio.NewScanner(defFile) - fileScanner.Split(bufio.ScanLines) - - ln := 0 - var lines []line - imports := map[string]bool{} - - for fileScanner.Scan() { - lineStr := strings.TrimSpace(fileScanner.Text()) - ln++ - - if lineStr == "" || strings.HasPrefix(lineStr, "#") || - strings.HasPrefix(lineStr, "/") { - continue - } - - lineData, err := parseLine(lineStr, imports) - if err != nil { - fmt.Printf("[Err] line %d, %s: \"%s\n", ln, err.Error(), lineStr) - continue - } - lineData.UseExt = useExt - - lines = append(lines, *lineData) - } - - fmt.Printf("Parsed %d definitions\n", len(lines)) - - outFile := try.File(os.Create(outFileName)) - - tmpl := template.Must(template.New("templ").Parse(gotry.TypesTemplate)) - - try.Check(tmpl.Execute(outFile, struct { - Definitions []line - Imports map[string]bool - PkgName string - UseExt bool - }{ - Definitions: lines, - Imports: imports, - PkgName: pkgName, - UseExt: useExt, - })) - - try.Check(defFile.Close()) - try.Check(outFile.Close()) - - try.Check(goFmt(outFileName)) - - return -} - -func parseLine(lineStr string, imports map[string]bool) (*line, try.Err) { - lineParts := strings.Split(lineStr, ";") - lineData := line{} - - if len(lineParts) < 2 { - return nil, try.NewErr("missing type name") - } - - // Parse variable name - variableRaw := strings.TrimSpace(lineParts[0]) - if match := variablePattern.FindStringSubmatch(variableRaw); match != nil { - lineData.Name = match[1] - lineData.WithSlice = match[2] != "" - } else { - return nil, try.NewErr("invalid variable name") - } - - // Parse type name(s) - for _, typeStr := range strings.Split(lineParts[1], ",") { - typeStr = strings.TrimSpace(typeStr) - if typeStr != "" { - lineData.Types = append(lineData.Types, typeStr) - } - } - if len(lineData.Types) == 0 { - return nil, try.NewErr("invalid type name") - } - - // Parse imports - for i := 2; i < len(lineParts); i++ { - pkgName := strings.TrimSpace(lineParts[i]) - imports[pkgName] = true - } - - return &lineData, nil -} - -func goFmt(goFile string) error { - return exec.Command("gofmt", "-s", "-w", goFile).Run() -} - -func main() { - defer try.CatchTrace(1) - - // Read flags - var definitionFile string - var targetDir string - var typeFile string - - flag.StringVar(&definitionFile, "def", path.Join("try", "types.csv"), - "Definition file") - flag.StringVar(&targetDir, "o", "try", "Target directory") - flag.StringVar(&typeFile, "of", "types", "Name of generated type definition file") - flag.Parse() - - try.Check(os.MkdirAll(targetDir, 0o777)) - - // Generate types - if _, e := os.Stat(definitionFile); os.IsNotExist(e) { - try.Check(try.NewErr("Definition file does not exist")) - } else { - try.Check( - parseDefinitions(definitionFile, path.Join(targetDir, typeFile+".go"), - path.Base(targetDir))) - } -} diff --git a/try/std_types.go b/try/std_types.go deleted file mode 100644 index 0d9865c..0000000 --- a/try/std_types.go +++ /dev/null @@ -1,290 +0,0 @@ -package try - -// gotry auto-generated type definitions. DO NOT EDIT. - -import ( - "io" - "net/http" - "net/url" - "os" -) - -// Bool is a helper method to handle errors of -// func() (bool, error) functions. -func Bool(v bool, err error) bool { - Check(err) - return v -} - -// Bools is a helper method to handle errors of -// func() ([]bool, error) functions. -func Bools(v []bool, err error) []bool { - Check(err) - return v -} - -// Byte is a helper method to handle errors of -// func() (byte, error) functions. -func Byte(v byte, err error) byte { - Check(err) - return v -} - -// Bytes is a helper method to handle errors of -// func() ([]byte, error) functions. -func Bytes(v []byte, err error) []byte { - Check(err) - return v -} - -// Rune is a helper method to handle errors of -// func() (rune, error) functions. -func Rune(v rune, err error) rune { - Check(err) - return v -} - -// Runes is a helper method to handle errors of -// func() ([]rune, error) functions. -func Runes(v []rune, err error) []rune { - Check(err) - return v -} - -// String is a helper method to handle errors of -// func() (string, error) functions. -func String(v string, err error) string { - Check(err) - return v -} - -// Strings is a helper method to handle errors of -// func() ([]string, error) functions. -func Strings(v []string, err error) []string { - Check(err) - return v -} - -// Int is a helper method to handle errors of -// func() (int, error) functions. -func Int(v int, err error) int { - Check(err) - return v -} - -// Ints is a helper method to handle errors of -// func() ([]int, error) functions. -func Ints(v []int, err error) []int { - Check(err) - return v -} - -// Int8 is a helper method to handle errors of -// func() (int8, error) functions. -func Int8(v int8, err error) int8 { - Check(err) - return v -} - -// Int8s is a helper method to handle errors of -// func() ([]int8, error) functions. -func Int8s(v []int8, err error) []int8 { - Check(err) - return v -} - -// Int16 is a helper method to handle errors of -// func() (int16, error) functions. -func Int16(v int16, err error) int16 { - Check(err) - return v -} - -// Int16s is a helper method to handle errors of -// func() ([]int16, error) functions. -func Int16s(v []int16, err error) []int16 { - Check(err) - return v -} - -// Int32 is a helper method to handle errors of -// func() (int32, error) functions. -func Int32(v int32, err error) int32 { - Check(err) - return v -} - -// Int32s is a helper method to handle errors of -// func() ([]int32, error) functions. -func Int32s(v []int32, err error) []int32 { - Check(err) - return v -} - -// Int64 is a helper method to handle errors of -// func() (int64, error) functions. -func Int64(v int64, err error) int64 { - Check(err) - return v -} - -// Int64s is a helper method to handle errors of -// func() ([]int64, error) functions. -func Int64s(v []int64, err error) []int64 { - Check(err) - return v -} - -// Uint is a helper method to handle errors of -// func() (uint, error) functions. -func Uint(v uint, err error) uint { - Check(err) - return v -} - -// Uints is a helper method to handle errors of -// func() ([]uint, error) functions. -func Uints(v []uint, err error) []uint { - Check(err) - return v -} - -// Uint8 is a helper method to handle errors of -// func() (uint8, error) functions. -func Uint8(v uint8, err error) uint8 { - Check(err) - return v -} - -// Uint8s is a helper method to handle errors of -// func() ([]uint8, error) functions. -func Uint8s(v []uint8, err error) []uint8 { - Check(err) - return v -} - -// Uint16 is a helper method to handle errors of -// func() (uint16, error) functions. -func Uint16(v uint16, err error) uint16 { - Check(err) - return v -} - -// Uint16s is a helper method to handle errors of -// func() ([]uint16, error) functions. -func Uint16s(v []uint16, err error) []uint16 { - Check(err) - return v -} - -// Uint32 is a helper method to handle errors of -// func() (uint32, error) functions. -func Uint32(v uint32, err error) uint32 { - Check(err) - return v -} - -// Uint32s is a helper method to handle errors of -// func() ([]uint32, error) functions. -func Uint32s(v []uint32, err error) []uint32 { - Check(err) - return v -} - -// Uint64 is a helper method to handle errors of -// func() (uint64, error) functions. -func Uint64(v uint64, err error) uint64 { - Check(err) - return v -} - -// Uint64s is a helper method to handle errors of -// func() ([]uint64, error) functions. -func Uint64s(v []uint64, err error) []uint64 { - Check(err) - return v -} - -// Float32 is a helper method to handle errors of -// func() (float32, error) functions. -func Float32(v float32, err error) float32 { - Check(err) - return v -} - -// Float32s is a helper method to handle errors of -// func() ([]float32, error) functions. -func Float32s(v []float32, err error) []float32 { - Check(err) - return v -} - -// Float64 is a helper method to handle errors of -// func() (float64, error) functions. -func Float64(v float64, err error) float64 { - Check(err) - return v -} - -// Float64s is a helper method to handle errors of -// func() ([]float64, error) functions. -func Float64s(v []float64, err error) []float64 { - Check(err) - return v -} - -// StrStr is a helper method to handle errors of -// func() (string, string, error) functions. -func StrStr(v string, v1 string, err error) (string, string) { - Check(err) - return v, v1 -} - -// X is a helper method to handle errors of -// func() (interface{}, error) functions. -func X(v interface{}, err error) interface{} { - Check(err) - return v -} - -// File is a helper method to handle errors of -// func() (*os.File, error) functions. -func File(v *os.File, err error) *os.File { - Check(err) - return v -} - -// Reader is a helper method to handle errors of -// func() (io.Reader, error) functions. -func Reader(v io.Reader, err error) io.Reader { - Check(err) - return v -} - -// Writer is a helper method to handle errors of -// func() (io.Writer, error) functions. -func Writer(v io.Writer, err error) io.Writer { - Check(err) - return v -} - -// Request is a helper method to handle errors of -// func() (*http.Request, error) functions. -func Request(v *http.Request, err error) *http.Request { - Check(err) - return v -} - -// Response is a helper method to handle errors of -// func() (*http.Response, error) functions. -func Response(v *http.Response, err error) *http.Response { - Check(err) - return v -} - -// Url is a helper method to handle errors of -// func() (*url.URL, error) functions. -func Url(v *url.URL, err error) *url.URL { - Check(err) - return v -} diff --git a/try/std_types_test.go b/try/std_types_test.go deleted file mode 100644 index c2fc44e..0000000 --- a/try/std_types_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package try - -import ( - "fmt" - "io" - "os" - "testing" -) - -func TestStrHelper_noThrow(t *testing.T) { - s := String(noThrow()) - if s != "test" { - t.Fail() - } -} - -func TestStrHelper_throw(t *testing.T) { - var err Err - defer Return(&err) - - String(throw()) - - t.Fail() // If everything works we are never here -} - -func TestStrStrHelper(t *testing.T) { - s1, s2 := StrStr(twoStrNoThrow()) - if s1 != "test" || s2 != "test" { - t.Fail() - } -} - -func Example_copyFile() { - copyFile := func(src, dst string) (err Err) { - defer Annotate(&err, fmt.Sprintf("copy %s %s", src, dst)) - - // These helpers are as fast as Check() calls - r := File(os.Open(src)) - defer Check(r.Close()) - - w := File(os.Create(dst)) - defer Handle(&err, func() { - os.Remove(dst) - }) - defer Check(w.Close()) - Empty(io.Copy(w, r)) - return nil - } - - err := copyFile("/notfound/path/file.go", "/notfound/path/file.bak") - if err != nil { - fmt.Println(err) - } - //nolint:lll - // Output: copy /notfound/path/file.go /notfound/path/file.bak: open /notfound/path/file.go: no such file or directory -} - -func BenchmarkTry_StringHelper(b *testing.B) { - for n := 0; n < b.N; n++ { - _ = String(noThrow()) - } -} - -func BenchmarkTry_XHelper(b *testing.B) { - for n := 0; n < b.N; n++ { - _ = X(noThrow()).(string) - } -} diff --git a/try/try.go b/try/try.go index f24576b..0c85b5f 100644 --- a/try/try.go +++ b/try/try.go @@ -46,8 +46,8 @@ type call struct { Line int `json:"l"` } -// FromErr wraps a standard error into a try-compatible one with extended stack info. -func FromErr(err error) Err { +// fromErr wraps a standard error into a try-compatible one with extended stack info. +func fromErr(err error) Err { // If the error is already try-compatible, return //nolint:errorlint cterr, ok := err.(Err) @@ -88,9 +88,9 @@ func FromErr(err error) Err { return terr } -// NewErr creates a new try-compatible error with extended stack info. -func NewErr(msg string) Err { - return FromErr(errors.New(msg)) +// newErr creates a new try-compatible error with extended stack info. +func newErr(msg string) Err { + return fromErr(errors.New(msg)) } // Error returns the standard go error message (initial message + annotations). @@ -144,41 +144,37 @@ func (e *tryErr) Annotate(msg string) { e.annotations = append(e.annotations, msg) } -// Empty is a helper method to handle errors of func() (string, error) functions. -func Empty(_ interface{}, err error) { - Check(err) -} - -// Any is as similar as proposed Go2 Try macro, but it's a function and it -// returns slice of interfaces. It has quite big performance penalty when -// compared to Check function. -func Any(args ...interface{}) []interface{} { - check(args) - return args -} - -// Check performs the error check for the given argument. If the err is nil, -// it does nothing. According the measurements, it's as fast as if err != nil -// {return err} on happy path. -func Check(err error) { +// To is a helper function to call functions which returns (error) +// and check the error value. If error occurs it panics the error where err2 +// handlers can catch it if needed. +func To(err error) { if err != nil { - panic(FromErr(err)) + panic(fromErr(err)) } } -// Checks the error status of the last argument. It panics with "wrong -// signature" if the last calling parameter is not error. In case of error it -// delivers it by panicking. -func check(args []interface{}) { - argCount := len(args) - last := argCount - 1 - if args[last] != nil { - err, ok := args[last].(error) - if !ok { - panic("wrong signature") - } - panic(FromErr(err)) - } +// To1 is a helper function to call functions which returns (any, error) +// and check the error value. If error occurs it panics the error where err2 +// handlers can catch it if needed. +func To1[T any](v T, err error) T { + To(err) + return v +} + +// To2 is a helper function to call functions which returns (any, any, error) +// and check the error value. If error occurs it panics the error where err2 +// handlers can catch it if needed. +func To2[T, U any](v1 T, v2 U, err error) (T, U) { + To(err) + return v1, v2 +} + +// To3 is a helper function to call functions which returns (any, any, any, error) +// and check the error value. If error occurs it panics the error where err2 +// handlers can catch it if needed. +func To3[T, U, V any](v1 T, v2 U, v3 V, err error) (T, U, V) { + To(err) + return v1, v2, v3 } // Handle is for adding an error handler to a function by defer. It's for diff --git a/try/try_test.go b/try/try_test.go index fac96ee..2e9bf2c 100644 --- a/try/try_test.go +++ b/try/try_test.go @@ -21,14 +21,12 @@ func twoStrNoThrow() (string, string, error) { return "test", "test", nil } func noThrow() (string, error) { return "test", nil } -func wrongSignature() (int, int) { return 0, 0 } - func recursion(a int) int { if a == 0 { return 0 } s, err := noThrow() - Check(err) + To(err) _ = s return a + recursion(a-1) } @@ -53,14 +51,14 @@ func noErr() error { return nil } -func TestAny_noError(t *testing.T) { - d := Any(noThrow()) - if d[0].(string) != "test" { +func Test_noError(t *testing.T) { + x := To1(noThrow()) + if x != "test" { t.Fail() } - d = Any(twoStrNoThrow()) - if d[0].(string) != "test" || d[1].(string) != "test" { + x, y := To2(twoStrNoThrow()) + if x != "test" || y != "test" { t.Fail() } } @@ -69,7 +67,7 @@ func TestDefault_Error(t *testing.T) { var err Err defer Return(&err) - Any(throw()) + To1(throw()) t.Fail() // If everything works we are never here } @@ -78,7 +76,7 @@ func TestAny_Error(t *testing.T) { var err Err defer Handle(&err, func() {}) - Any(throw()) + To1(throw()) t.Fail() // If everything works we are never here } @@ -87,13 +85,13 @@ func panickingHandle() { var err Err defer Handle(&err, func() {}) - Any(wrongSignature()) + panic("test") } func TestPanickingCarryOn_Handle(t *testing.T) { defer func() { if recover() == nil { - t.Error("panics should went thru when not our errors") + t.Error("panics should go through when not our errors") } }() panickingHandle() @@ -102,7 +100,7 @@ func TestPanickingCarryOn_Handle(t *testing.T) { func panickingCatchAll() { defer CatchAll(func(err Err) {}, func(v interface{}) {}) - Any(wrongSignature()) + panickingHandle() } func TestPanickingCatchAll(t *testing.T) { @@ -118,7 +116,7 @@ func panickingReturn() { var err Err defer Return(&err) - Any(wrongSignature()) + panickingHandle() } func TestPanicking_Return(t *testing.T) { @@ -133,7 +131,7 @@ func TestPanicking_Return(t *testing.T) { func panickingCatch() { defer Catch(func(err Err) {}) - Any(wrongSignature()) + panickingHandle() } func TestPanicking_Catch(t *testing.T) { @@ -150,13 +148,13 @@ func TestCatch_Error(t *testing.T) { // fmt.Printf("error and defer handling:%s\n", err) }) - Any(throw()) + To1(throw()) t.Fail() // If everything works we are never here } func TestNewTryErr(t *testing.T) { - tryErr := NewErr("I f*cked up") + tryErr := newErr("I f*cked up") callStack := tryErr.CallStackString() if !strings.HasPrefix(callStack, "ERROR: I f*cked up\n") { @@ -172,7 +170,7 @@ func TestNewTryErr(t *testing.T) { } func TestGetData(t *testing.T) { - tryErr := NewErr("I f*cked up") + tryErr := newErr("I f*cked up") tryErr.Annotate("test1") tryErr.Annotate("test2") data := tryErr.GetData() @@ -199,7 +197,7 @@ func TestGetData(t *testing.T) { func TestErrCompare(t *testing.T) { err := errors.New("TestError") - tryErr := FromErr(err) + tryErr := fromErr(err) if !errors.Is(tryErr, err) { t.Fail() @@ -209,7 +207,7 @@ func TestErrCompare(t *testing.T) { func TestReturnStd(t *testing.T) { tf := func() (err error) { defer ReturnStd(&err) - String(throw()) + To1(throw()) return } @@ -221,11 +219,11 @@ func TestReturnStd(t *testing.T) { } func TestCheckTryErr(t *testing.T) { - testErr := NewErr("TestErr") + testErr := newErr("TestErr") tf := func() (err Err) { defer Return(&err) - Check(testErr) + To(testErr) return } @@ -239,14 +237,14 @@ func TestCheckTryErr(t *testing.T) { func ExampleReturn() { var err Err defer Return(&err) - Any(noThrow()) + To1(noThrow()) // Output: } func ExampleAnnotate() { annotated := func() (err Err) { defer Annotate(&err, "annotated") - Any(throw()) + To1(throw()) return err } err := annotated() @@ -258,7 +256,7 @@ func ExampleAnnotate_deferStack() { annotated := func() (err Err) { defer Annotate(&err, "annotated 2nd") defer Annotate(&err, "annotated 1st") - Any(throw()) + To1(throw()) return err } err := annotated() @@ -271,7 +269,7 @@ func ExampleHandle() { defer Handle(&err, func() { err.Annotate(fmt.Sprintf("error with (%d, %d)", a, b)) }) - Any(throw()) + To1(throw()) return err } err := doSomething(1, 2) @@ -290,34 +288,34 @@ func BenchmarkOldErrorCheckingWithIfClause(b *testing.B) { func BenchmarkAny(b *testing.B) { for n := 0; n < b.N; n++ { - Any(noThrow()) + To1(noThrow()) } } func BenchmarkAny_ErrVar(b *testing.B) { for n := 0; n < b.N; n++ { _, err := noThrow() - Any(err) + To(err) } } func BenchmarkCheckInsideCall(b *testing.B) { for n := 0; n < b.N; n++ { - Check(noErr()) + To(noErr()) } } func BenchmarkCheckVarCall(b *testing.B) { for n := 0; n < b.N; n++ { err := noErr() - Check(err) + To(err) } } func BenchmarkCheck_ErrVar(b *testing.B) { for n := 0; n < b.N; n++ { _, err := noThrow() - Check(err) + To(err) } } diff --git a/try/types.csv b/try/types.csv deleted file mode 100644 index 5c031f6..0000000 --- a/try/types.csv +++ /dev/null @@ -1,29 +0,0 @@ -Bool+s;bool -Byte+s;byte -Rune+s;rune -String+s;string - -Int+s;int -Int8+s;int8 -Int16+s;int16 -Int32+s;int32 -Int64+s;int64 - -Uint+s;uint -Uint8+s;uint8 -Uint16+s;uint16 -Uint32+s;uint32 -Uint64+s;uint64 - -Float32+s;float32 -Float64+s;float64 - -StrStr;string, string -X;interface{} - -File;*os.File;os -Reader;io.Reader;io -Writer;io.Writer;io -Request;*http.Request;net/http -Response;*http.Response;net/http -Url;*url.URL;net/url diff --git a/try/types.tmpl b/try/types.tmpl deleted file mode 100644 index 4d1a62d..0000000 --- a/try/types.tmpl +++ /dev/null @@ -1,31 +0,0 @@ -package {{.PkgName}} - -// gotry auto-generated type definitions. DO NOT EDIT. - -import ( -{{- if .UseExt }} -"code.thetadev.de/ThetaDev/gotry/try" -{{- end}} -{{- range $pkg, $b := .Imports}} - "{{$pkg}}" -{{- end}} -) -{{range $d := .Definitions }} -// {{$d.Name}} is a helper method to handle errors of -// func() ({{range $i, $t := $d.Types}}{{$t}}, {{end}}error) functions. -func {{$d.Name}}({{range $i, $t := $d.Types}}v{{if $i}}{{$i}}{{end}} {{$t}}, {{end}}err error) ( -{{- range $i, $t := $d.Types}}{{if $i}}, {{end}}{{$t}}{{end}}) { - {{if .UseExt}}try.{{end}}Check(err) - return {{range $i, $t := $d.Types}}{{if $i}}, v{{$i}}{{else}}v{{end}}{{end}} -} -{{- if $d.WithSlice}} - -// {{$d.Name}}s is a helper method to handle errors of -// func() ({{range $i, $t := $d.Types}}[]{{$t}}, {{end}}error) functions. -func {{$d.Name}}s({{range $i, $t := $d.Types}}v{{if $i}}{{$i}}{{end}} []{{$t}}, {{end}}err error) ( -{{- range $i, $t := $d.Types}}{{if $i}}, {{end}}[]{{$t}}{{end}}) { - {{if .UseExt}}try.{{end}}Check(err) - return {{range $i, $t := $d.Types}}{{if $i}}, v{{$i}}{{else}}v{{end}}{{end}} -} -{{- end}} -{{end}}