Good point Harri,

This is what the correct version will look like using this proposal 

func CopyFile(src, dst string) error {
r, err := os.Open(src) *orelse* return fmt.Errorf("copy %s %s: %v", src, 
dst, err)
defer r.Close()

w, err := os.Create(dst); *orelse* return fmt.Errorf("copy %s %s: %v", src, 
dst, err)
err := io.Copy(w, r) *orelse* {
w.Close()
os.Remove(dst)
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}

err := w.Close() *orelse* {
os.Remove(dst)
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
}

In a more complex func, the error formatting/handling code can be further 
deduplicated by extracting it into a closure. 
e.g., 

func CopyFile(src, dst string) error {
copyErr:= func(err error) {
return fmt.Errorf("copy %s %s: %v", src, dst, err)
} 
r, err := os.Open(src) *orelse* return copyErr(err) 
defer r.Close()

w, err := os.Create(dst); *orelse* return copyErr(err)
err := io.Copy(w, r) *orelse* {
w.Close()
os.Remove(dst)
return copyErr(err)
}

err := w.Close() *orelse* {
os.Remove(dst)
return copyErr(err)
}
}

On Sunday, July 30, 2023 at 8:17:31 AM UTC-6 Harri L wrote:

> IMHO, you have used the irrelevant example (== 2nd code block) from Russ 
> Cox's paper. The paper says:
> > This code is not nice, not clean, not elegant, *and still wrong:* like 
> the previous version, it does not remove dst when io.Copy or w.Close
>  fails.
>
> I want to compare your proposal with the third example from the paper, 
> which does (proper) error annotation and cleanup. Thanks.
> On Sunday, July 30, 2023 at 8:57:15 AM UTC+3 DrGo wrote:
>
>> I looked at the long list of proposals to improve error handling in go 
>> but I have not seen the one I am describing below. If I missed a similar , 
>> can you pls direct me to where I can find it. If not what do you think of 
>> this approach. 
>>
>> This involves introducing a new keyword "orelse" that is a syntactic 
>> sugar for an "if err!=nil" block.
>>
>> The example code in Russ Cox's paper[1] will look something like this:
>>
>> func CopyFile(src, dst string) error {
>>
>> r, err := os.Open(src) orelse return err 
>>
>> defer r.Close()
>>
>> w, err := os.Create(dst) orelse return err
>>
>> defer w.Close()
>>
>>   err = io.Copy(w, r) orelse return err
>>
>> err = w.Close() orelse return err
>>
>> }
>>
>> It is an error to not return an error from an orelse block.
>>
>> In my eyes, this has the same explicitness and flexibility of the current 
>> style but is significantly less verbose. It permits ignoring the error, 
>> returning it as is or wrapping it. Because orelse is not used for any other 
>> purpose, it would be easy for reviewers and linters to spot lack of error 
>> handling.  
>>
>> It also works well with named returns. e.g., 
>>
>> func returnsObjorErro() (obj Obj, err error) {
>>
>>   obj, err := createObj() orelse return  //returns nil and err
>>
>> } 
>>
>> otherwise orelse is like "else" so e.g., it can be followed by a block if 
>> additional cleanup or error formatting etc is needed before returning, eg 
>> w, err := os.Create(dst) orelse {
>>   ....
>>   return err 
>> }
>>
>> Similarity to "else" hopefully means that it is easy to learn. It is 
>> obviously backward compatible  
>>
>> What do you think?
>>
>> [1] 
>> https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md
>>
>

-- 
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/db03dc82-6a11-4593-9f20-d8c5863c1e4an%40googlegroups.com.

Reply via email to