Discussing implementations of the (returns..., error) idiom from golang in other languages, I noted a common thing: non-go developers often conceptualized this as a back channel and didn't intuit that it's just a return-value convention.
This lead me to a new idea for addressing the excess verbosity of the majority of trivial error handling in golang, that is primarily just an additional reflection tag for functions and a mechanism to leverage that from calling sites. The error slot, written `error<-`. As a return type, it is just the type `error` but tags the function as having return field N be recognized as the error slot. ``` func ReadFile1(filename string) ([]byte, bool, error) // *can* optionally be written func ReadFile2(filename string) ([]byte, bool, error<-) ``` - Actual type is just 'error', - One per function, - Position doesn't matter, - Named/anoymous, - reflection gains a method that gives -1 for no error slot otherwise >= 0 denoting which return field is official error slot, - parsing: very context-specific cases, potentially even a dedicated token/symbol, Beyond syntax support, this requires no compatibility breaking changes, but one such break IS proposed: - Failing to forward/capture the error slot of a method in a function without an error slot be a compile error, ``` // slotted func AnError() error<- { return io.EOF } // old code, unslotted func OldError() error { return io.EOF } // old code, unslotted func OldFunction() error { OldError() // valid as currently AnError() // compile error suggesting `_ = AnError()` _ = AnError() // valid but vet warned return AnError() // valid } ``` Second, a change to provide an implicit nil-or-return shorthand: replace the field's capture on the left side with "error<-". ``` func Old() (int, error, bool, error) // Who knows func New() (int, error<-, bool, error) // They have their reasons func Caller() (err error<-) { // Must be slotted to use new syntax. // Old code is still absolutely valid. if i, e1, b, e2 := Old(); e1 != nil { return e1 } // Also still absolutely valid. if i, e1, b, e2 := New(); e1 != nil { return e2 } // Because Old doesn't specify which is a slot, we can use either: _, error<-, _, _ = Old() // aka: if _, err, _, _ = Old(); err != nil { return } _, _, _, error<- = Old() // aka: if _, _, _, err = Old(); err != nil { return } // Slotted functions are constrained to the error slot return tho. _, error<-, _, _ = New() // valid // _, _, _, error<- = New() // invalid, slot mismatch } ``` A final benefit of marking your function slotted is that if you fail to capture a call slot yourself, it introduces an implicit panic ``` func Panicy() error<- { Old() // no change New() // if new's error slot != nil, panics. vet warning. } ``` Some of the people I discussed this with immediately went to method chaining, but I think the above change actually already brings that approach to a more beautiful middle ground: A couple folks asked me about chaining: Special-case a method returning one value and an error slot: ``` func OpenFile(name string) (*File, error<-) func (f *File) ReadRaw() (*RawStuff, error<-) func (r *RawStuff) Decode() (*Data, error<-) // Old Style func StructFromFile1(name string) (data *Data, err error) { var file *File var raw *RawStuff file, err = OpenFile(name) if err == nil { raw, err = file.ReadRaw() if err == nil { data, err = raw.Decode() } } return } // Rusty, too terse and prone to creating hard to decipher multi-part mega-statements. func StructFromFile2(name string) (*Data, error<-) { return OpenFile(name).ReadRaw().Decode() } // A properly go-beautiful style: func StructFromFile3(name string) (*Data, error<-) { file, error<- := OpenFile(name) raw, error<- := file.ReadRaw() return raw.Decode() } ``` -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/2025acf5-a7d0-48be-8a29-d9ed717a7566n%40googlegroups.com.