Thanks for the valuable feedback, The verbosity of error handling is the number one concern for Go developers in the most recent survey. So there is a need for doing something about it.. except that there are many possibly conflicting requirements outlined by the Go team. The problem with the abbreviated if err!= nil in your example: if x,err := something() ; err != nil { handleErrorAndReturn } is that x is local to the if scope and often that won't work forcing the more verbose: x,err := something() if err != nil { handleErrorAndReturn } If you have few of those as is the case in io programs; there is real impact on the readability of the code. the oresle approach avoids that problem (the x stays in the scope of the func).
x,err := something() orelse { handleErrorAndReturn } You do not think this is a significant reduction in boilerplate? The only thing that will do a better job is a try-catch which is not acceptable to the Go team (fortunately). why the line-by-line would break with orelse? they are working fine with the one-liner you cited: if x,err := something() ; err != nil Why it won't work with one time retires? That is like one time retires won't work in an if-else block. Thanks again, On Monday, July 31, 2023 at 3:59:50 PM UTC-6 Tim Casey wrote: > > > I do not think this reduces boilerplate code. This compacts it, which is > different. > > I think any one-liner-return-on-err makes the language harder to debug. > It is very common breakpoints are set for exceptional cases, which tend to > be surprising. If the test and the return are on the same line then all of > the line-by-line tools will break down, at least a little bit. > > If you see: > x,err := something() ; err != nil { > handleErrorAndReturn > } > > At the very least, the template will not work for things like one time > retries, if error do something else, log the error and > DoSomethingAdditional(). This would be a sub scope and in golang i would > expect this to have '{}' as part of the scope shift. If this is > acceptable, then you are very likely to be on a separate line in any > event. So the original looks like: > > err := io.Copy(w, r) *orelse* { > DoSomethingElse() > } > > This means the only 'boilerplate' is 'orelse' <- '; err != nil', which > seems rather expensive for this error handling. > > As a slight change of subject, I find the whole discussion about 'saving' > boilerplate to be well over-stated, too much work and energy (at least by > me as an outside observer). Having something which fits within the design > of the language, making it a developer centric language, would seem to > fight with any one-line-template approach. > > tim > > > > > > The test and the handle all fit on one line. I dont think having a > single line return, like perl 'next if STATEMENT' style fits within golang > language goals. > > On Mon, Jul 31, 2023 at 8:18 AM DrGo <salah....@gmail.com> wrote: > >> Me too but I do not have high hopes >> >> >> On Monday, July 31, 2023 at 12:10:24 AM UTC-6 Mark wrote: >> >>> Given that this proposal is to reduce boilerplate, and assuming the >>> semantic issues could be solved, it seems to me that the 'return' is >>> redundant (i.e., could be implicit) and that 'orelse' could be done with >>> the existing 'else' keyword, i.e., >>> >>> ``` >>> result, err := someCall() else rest, err >>> ``` >>> Anyway, I really do hope the long-winded error syntax gets solved >>> somehow! >>> >>> On Monday, July 31, 2023 at 5:41:49 AM UTC+1 DrGo wrote: >>> >>>> func myFirstFunction() (string, err) { >>>> >>>> result, err := myFunction() orelse return rest, err >>>> >>>> } >>>> >>>> On Sunday, July 30, 2023 at 9:27:27 PM UTC-6 Marcello H wrote: >>>> >>>>> I think the current error handling is just fine. >>>>> For the extra typing, they invented keyboard snippets and such. >>>>> >>>>> But for this proposal, I would like to see how a return with multiple >>>>> values would look to get a better understanding. >>>>> ``` >>>>> // translate this in the proposed solution? >>>>> func myFirstFunction() (string, err) { >>>>> result, err := myFunction() >>>>> if err != nill { >>>>> return rest, err >>>>> } >>>>> } >>>>> ``` >>>>> >>>>> Op maandag 31 juli 2023 om 04:32:01 UTC+2 schreef DrGo: >>>>> >>>>>> Another possibility Jeremy is that the orelse block is executed if >>>>>> any of the returned error values is not nil. >>>>>> >>>>>> On Sunday, July 30, 2023 at 8:14:58 PM UTC-6 DrGo wrote: >>>>>> >>>>>>> Thanks... >>>>>>> yes indeed. Too many requirements but I think this solution comes >>>>>>> close to meeting them. If a rare function returns more than one error >>>>>>> value >>>>>>> (yet to see one in the wild) then the compiler should reject orelse use >>>>>>> and >>>>>>> the user can fallback on the (the if err!= nil) approach. >>>>>>> >>>>>>> On Sunday, July 30, 2023 at 6:02:57 PM UTC-6 Jeremy French wrote: >>>>>>> >>>>>>>> Also, errors are values, which means - although uncommon - a >>>>>>>> function could return two or more error values. Which would orelse >>>>>>>> evaluate? Even if you arbitrarily chose one, that would violate the >>>>>>>> explicit vs implicit code flow principle. >>>>>>>> >>>>>>>> My sympathies, OP. I too hate the "if err!= nil" boilerplate, and >>>>>>>> have suggested my own idea for fixing it, which was similarly >>>>>>>> dismantled >>>>>>>> for good reasons by those more knowledgeable than me. The truth is, >>>>>>>> this >>>>>>>> problem/issue has so many restrictions placed on it (currently >>>>>>>> idiomatic >>>>>>>> principles, backwards compatibility promise, explicit vs implicit, >>>>>>>> etc) >>>>>>>> that the set of possible solutions is VERY narrow, possibly infinitely >>>>>>>> so. >>>>>>>> >>>>>>>> On Sunday, July 30, 2023 at 3:51:49 PM UTC-4 Brian Candler wrote: >>>>>>>> >>>>>>>> err := io.Copy(w, r) *orelse* { >>>>>>>> w.Close() >>>>>>>> os.Remove(dst) >>>>>>>> return fmt.Errorf("copy %s %s: %v", src, dst, err) >>>>>>>> } >>>>>>>> >>>>>>>> My question still stands. Semantically, what value exactly does the >>>>>>>> "orelse" condition test is not equal to nil? >>>>>>>> >>>>>>>> - does it test the value from the preceding assignment? If so, is >>>>>>>> "orelse" only valid immediately following an assignment expression? >>>>>>>> The >>>>>>>> original posting didn't say this. And if it *is* linked to an >>>>>>>> assignment >>>>>>>> expression which assigns multiple values, does it only look at the >>>>>>>> last >>>>>>>> value? (Again, that was not specified) >>>>>>>> >>>>>>>> - does it always test a variable called "err"? The original posting >>>>>>>> said it was equivalent to "if err!=nil" but a later post contradicted >>>>>>>> this >>>>>>>> >>>>>>>> - does it test the value from the 'return' expression at the end of >>>>>>>> the block following orelse? Except in this case, it can't because it's >>>>>>>> buried inside fmt.Errorf >>>>>>>> >>>>>>>> On Sunday, 30 July 2023 at 17:55:34 UTC+1 DrGo wrote: >>>>>>>> >>>>>>>> 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...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/b87365af-9a72-4f8d-ad0b-1ee69cc1ad35n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/golang-nuts/b87365af-9a72-4f8d-ad0b-1ee69cc1ad35n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- 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/9453a6fe-04c2-4c6d-88e9-4ec1cbd59361n%40googlegroups.com.