"or main could be lazy and let `error<-` panic when err != nil:"
* would require that `action`'s signature be `func action() (string, error<-)` On Monday, January 9, 2023 at 12:10:25 PM UTC-8 Oliver Smith wrote: > A complete example (followed by the code it replaced): > > ``` > package main > > import ( > "fmt" > "os" > ) > > func getMotd() (string, error<-) { > motd, error<- := os.ReadFile("/etc/motd") > return "MOTD:\n---\n" + string(motd) + "\n---\n", nil > } > > func getPwd() (string, error<-) { > pwd, error<- := os.Getwd() > return "PWD:\n" + pwd + "\n", nil > } > > func action() error { > motd, error<- := getMotd() > pwd, error<- := getPwd() > > fmt.Println(motd, pwd) > > return nil > } > > func main() { > if err := action(); err != nil { > fmt.Printf("ERROR: %s\n", err) > } > } > ``` > The Go Playground (golang.com) <https://play.golang.com/p/nk3ePQhjEWC> > > or main could be lazy and let `error<-` panic when err != nil: > ``` > func main() { > action() > } > ``` > > The current go code would be: > > ``` > package main > > import ( > "fmt" > "os" > ) > > func getMotd() (string, error) { > motd, err := os.ReadFile("/etc/motd") > if err != nil { > return "", err > } > return "MOTD:\n---\n" + string(motd) + "\n---\n", nil > } > > func getPwd() (string, error) { > pwd, err := os.Getwd() > if err != nil { > return "", err > } > return "PWD:\n" + pwd + "\n", nil > } > > func action() error { > motd, err := getMotd() > if err != nil { > return err > } > pwd, err := getPwd() > if err != nil { > return err > } > > fmt.Println(motd, pwd) > > return nil > } > > func main() { > if err := action(); err != nil { > fmt.Printf("ERROR: %s\n", err) > } > } > ``` > https://play.golang.com/p/2_pk-FNv-dk > On Tuesday, December 27, 2022 at 3:52:41 PM UTC-8 Oliver Smith wrote: > >> 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/18eeb7a8-defc-4cfd-a07b-63b04be4161en%40googlegroups.com.