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.