>> You do not think this is a significant  reduction in boilerplate?

I understand people having a complaint about the verbosity of error
handling.  But, this follows C code error handling.  So to me, it is not
all *that* bad.
I think the measurable reduction in boilerplate code is ' ; err != nil' for
' orelse '.   And I do not believe this is worth a keyword.  Some of the
context is  being used to C.  And another aspect is being used to perl and
its one liners.  With perl, the debugger is not something which is close to
gdb/adb or the like.  So the comparison is not about saving code.

I would suggest, if I had a bold idea (and probably dumb), to have a
functional way to handle this.   Something like:

    HandleErrorChain( todoList []func() (TYPE,error), errorHandler func ()
TYPE, error ) (TYPE, error)

Which means, I have a list of things I want to do and I want the error
handling to be all the same for all of them.  Then the *chain* of things
would make sense with a single handler.  This has the expense of being
kinda odd so at the very least it would need idiomatic polishing.  I also
think I am too ignorant to have a real say in any of this.

>> Why it won't work with one time retires? That is like one time retires
won't work in an if-else block

I think there is a bit of talking past each other here.  Or at least I
dont understand.  I think orelse is too specific to be helpful.  That is,
it is too precise to reduce a large swath of what might look like error
handling code, because error handling code can at times be specific.  The
first dumb example I came up with is a simple one-time retry, which I have
put in code at times.  It is usually ugly, but effective:

    v,err := dosomething()
    if err != nil {
        v,err = dosomething()
    }
    if err != nil {
        handleError(err)
   }
   importantOperation(v)

This with the token:

    if v,err := dosomething() orelse {
        v,err = dosomething() orelse {
            handleError()
        }
    }
    importantOperation(v)

The savings is the two 'err != nil' lines.

If I take a step back, some of what I am reacting to is how much it is
discussed.  It *feels*, at least to me as an ignorant person in this
context, as if people were not handling errors previously.  Golang is
forcing this now and the resulting lines of code look like 'too much'
compared to previous lines of code.  But I think this is a direct design
goal.  If the keyword vs lines of code/tokenspace is worth it, so be it.
Who am I to say.  If we are truely circling on a way to handle errors in a
chain, then the chain aspect is at least as important as any one line, and
up to this point has largely been ignored.

In any event, i dont mean to be argumentative or even contrarian.  Sorry if
it comes across that way.

tim


On Mon, Jul 31, 2023 at 4:46 PM DrGo <salah.mah...@gmail.com> wrote:

> 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
> <https://groups.google.com/d/msgid/golang-nuts/9453a6fe-04c2-4c6d-88e9-4ec1cbd59361n%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/CAMyFqkTBYHk0x9YRtdjd58ob-P21HvEtNmh6yvtzk%2BZnqkxACw%40mail.gmail.com.

Reply via email to