"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.

Reply via email to