Thanks Tim for patiently explaining your perspective. Much appreciated.
Please see my reply to Marcelo H showing using real life code that the
outcome goes much further than replacing the err!= nil bit.
On Monday, July 31, 2023 at 7:20:18 PM UTC-6 Tim Casey wrote:
>
> >> 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 <[email protected]> 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 <[email protected]> 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 [email protected].
>>>> 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 [email protected].
>>
> 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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/14b505e9-9061-4a55-a309-69536dffcd85n%40googlegroups.com.