Stories
Slash Boxes
Comments

SoylentNews is people

posted by martyb on Wednesday July 17 2019, @05:37PM   Printer-friendly
from the No!-Try-not.-Do,-or-do-not.-There-is-no-try.-YODA dept.

The Go language will not be adding a "try" keyword in the next major version, despite this being a major part of what was proposed for version 1.14.

Go, an open source language developed by Google, features static typing and native code compilation. It is around the 15th most popular language according to the Redmonk rankings.

Error handling in Go is currently based on using if statements to compare a returned error value to nil. If it is nil, no error occurred. This requires developers to write a lot of if statements.

"In general Go programs have too much code-checking errors and not enough code handling them," wrote Google principal engineer Russ Cox in an overview of the error-handling problem in Go.

A try statement was proposed to help reduce the coding burden. Upon further reflection:

That proposal has now been abandoned. Robert Griesemer, one of the original designers of Go, announced the decision in a post yesterday.

[...] “Making an exit point of a function that isn't a return, and is meant to be commonplace, may lead to much less readable code,” said one user.

The outcome is a good one insofar as the Go community has proved able to make and withdraw a major proposal without rancour. And as for error handling, no doubt the team will, um, try again.


Original Submission

 
This discussion has been archived. No new comments can be posted.
Display Options Threshold/Breakthrough Mark All as Read Mark All as Unread
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
  • (Score: 0) by Anonymous Coward on Wednesday July 17 2019, @06:35PM (33 children)

    by Anonymous Coward on Wednesday July 17 2019, @06:35PM (#868140)

    I wish there were a way to break to a specific block level.

    break (2) ==> break out 2 levels from the inside

    break (-1) ==> break to the top level of the procedure minus one

  • (Score: 2) by DannyB on Wednesday July 17 2019, @06:38PM

    by DannyB (5839) Subscriber Badge on Wednesday July 17 2019, @06:38PM (#868142) Journal

    Maybe I Miss. Understand. But that sounds like a procedure would need to have some idea of who was calling it.

    --
    People today are educated enough to repeat what they are taught but not to question what they are taught.
  • (Score: 1) by nitehawk214 on Wednesday July 17 2019, @06:53PM (18 children)

    by nitehawk214 (1304) on Wednesday July 17 2019, @06:53PM (#868153)

    I had a friend that advocated this. Java has a "break with label" which is really just a goto. C# also supports a direct goto, as does most other c-derived languages.

    I don't even recall the last time I used a break statement outside of a switch. I used to use them all the time; but with more languages supporting advanced collections and lambdas, it leans to cleaner code not using breaks.

    --
    "Don't you ever miss the days when you used to be nostalgic?" -Loiosh
    • (Score: 2) by tangomargarine on Wednesday July 17 2019, @07:09PM (10 children)

      by tangomargarine (667) on Wednesday July 17 2019, @07:09PM (#868164)

      Java has a "break with label" which is really just a goto.

      Not exactly. From what I understand, you can only use it to descope to a later line number, within the same function. It's very much not an unconditional jump.

      The program execution resumes from the first statement encountered after the enclosing labeled break statement.

      --
      "Is that really true?" "I just spent the last hour telling you to think for yourself! Didn't you hear anything I said?"
      • (Score: 2) by DannyB on Wednesday July 17 2019, @07:36PM (9 children)

        by DannyB (5839) Subscriber Badge on Wednesday July 17 2019, @07:36PM (#868176) Journal

        According to this [geeksforgeeks.org]. You can use continue instead of break. You can jump backward as well as forward. You do not have to do it within a switch statement.

        It is restricted to be within the same function. But I do not see any obviously useful porpoise for being able to 'goto' outside of the current function.

        --
        People today are educated enough to repeat what they are taught but not to question what they are taught.
        • (Score: 2) by All Your Lawn Are Belong To Us on Wednesday July 17 2019, @07:59PM (3 children)

          by All Your Lawn Are Belong To Us (6553) on Wednesday July 17 2019, @07:59PM (#868185) Journal

          If you want to goto outside of a function then why not use a function call or a GOSUB. Porpoises like to travel with subs after all.
          (And more seriously, I suppose if you wanted to terminate a running function and purposely drive yourself somewhere other than what called it you'd want a goto.... otherwise why not jump to the bottom of your function and let it terminate naturally... ? )

          --
          This sig for rent.
          • (Score: 2) by tangomargarine on Wednesday July 17 2019, @08:52PM (1 child)

            by tangomargarine (667) on Wednesday July 17 2019, @08:52PM (#868212)

            If you want to goto outside of a function then why not use a function call or a GOSUB.

            The obvious answer is, because that doesn't let you discard your context. But good practice means that should be a rare desire anyway.

            If you absolutely feel you *need* a goto in Java, you can somewhat cumbersomely simulate it with a try-catch and purposely throwing an Exception. Which is also basically a comefrom [wikipedia.org] :)

            --
            "Is that really true?" "I just spent the last hour telling you to think for yourself! Didn't you hear anything I said?"
          • (Score: 1, Redundant) by DannyB on Thursday July 18 2019, @01:10PM

            by DannyB (5839) Subscriber Badge on Thursday July 18 2019, @01:10PM (#868477) Journal

            I would replace all GOTO with GOSUB for reasons of artistry and fashion.

            --
            People today are educated enough to repeat what they are taught but not to question what they are taught.
        • (Score: 2) by tangomargarine on Wednesday July 17 2019, @08:55PM (4 children)

          by tangomargarine (667) on Wednesday July 17 2019, @08:55PM (#868214)

          It doesn't "jump backward" any more than to the top of the nested block you're in, though. To be "really just a goto" you need to be able to jump to an arbitrary point in execution, which would include across function boundaries. It may not be super *useful* but let's not confuse our definitions by saying this is "basically goto" when it has all these restrictions built into it.

          --
          "Is that really true?" "I just spent the last hour telling you to think for yourself! Didn't you hear anything I said?"
          • (Score: 2) by DannyB on Thursday July 18 2019, @01:12PM (3 children)

            by DannyB (5839) Subscriber Badge on Thursday July 18 2019, @01:12PM (#868478) Journal

            If you can jump to any label within a certain construct, how is that not a GOTO ?

            Would any GOSUB smell as sweet?

            --
            People today are educated enough to repeat what they are taught but not to question what they are taught.
            • (Score: 2) by tangomargarine on Thursday July 18 2019, @02:50PM (1 child)

              by tangomargarine (667) on Thursday July 18 2019, @02:50PM (#868511)

              If you can jump to any label within a certain construct, how is that not a GOTO ?

              How many more times do I have to say this?

              It doesn't "jump backward" any more than to the top of the nested block you're in, though. To be "really just a goto" you need to be able to jump to an arbitrary point in execution, which would include across function boundaries.

              Wikipedia:

              GoTo (goto, GOTO, GO TO or other case combinations, depending on the programming language) is a statement found in many computer programming languages. It performs a one-way transfer of control to another line of code; in contrast a function call normally returns control. The jumped-to locations are usually identified using labels, though some languages use line numbers. At the machine code level, a goto is a form of branch or jump statement.

              Jump instructions [wikibooks.org] are literally "resume execution at line X". They don't care about context at all.

              The Java goto is a strict subset of gotos as generally understood, since the...compiler (or whatever it is they call the thing in Java that makes bytecode) checks the context where the label you're trying to jump to is located.

              Gosubs aren't gotos either. If it returns, it's a function call.

              --
              "Is that really true?" "I just spent the last hour telling you to think for yourself! Didn't you hear anything I said?"
              • (Score: 2) by DannyB on Thursday July 18 2019, @05:04PM

                by DannyB (5839) Subscriber Badge on Thursday July 18 2019, @05:04PM (#868588) Journal

                I do understand the difference between gosubs and gotos, once long ago programming WANG BASIC and TRS-80, etc.

                I've never needed to use a goto in Java. (Or C, or Pascal for that matter). Structured programming really does eliminate goto's.

                So I looked more closely at the link I gave, and I see that in Java the labels are more limited than I realized in where they can be placed. Surprise. But I've never need to use a goto since spring 1982. After that it was all Pascal and some bits of x86 and 68000 for me until the early 1990s.

                --
                People today are educated enough to repeat what they are taught but not to question what they are taught.
            • (Score: 2) by tangomargarine on Thursday July 18 2019, @02:54PM

              by tangomargarine (667) on Thursday July 18 2019, @02:54PM (#868512)

              And you can't jump to *any* label within a function either. As I said.


              void foo()
              {
                  label A:
                  code
                  code
                  code
                  label B:
                  while(true)
                  {
                      goto _;
                  }
              }

              Putting "B" in the blank will work. Putting "A" there will cause the compiler to yell at you.

              --
              "Is that really true?" "I just spent the last hour telling you to think for yourself! Didn't you hear anything I said?"
    • (Score: 3, Insightful) by Thexalon on Wednesday July 17 2019, @07:17PM (1 child)

      by Thexalon (636) on Wednesday July 17 2019, @07:17PM (#868167)

      The main upside of a "break" is to short-circuit when possible, but you're right that it's frequently unnecessary.

      One refactor that also eliminates "break", especially with multiple layers, is an early "return", combined with making the inside of a block into a method. Or in pseudocode, this:

      b = get_some_collection();
      foreach (a in b) {
          break_out = false;
          foreach (c in a) {
              if (c.condition()) {
                   break_out = true;
                   break;
              }
              // do some more stuff to c
          }
          if (break_out) {
              break;
          }
      }
      // continue doing stuff with b

      becomes this:

      function do_something_with_this_kind_of_collection(b) {
          foreach (a in b) {
              foreach (c in a) {
                  if (c.condition()) {
                       return b;
                  }
                  // do some more stuff to c
              }
          }
          return b;
      }
      b = get_some_collection();
      b = do_something_with_this_kind_of_collection(b);
      // continue doing stuff with b

      It's up to you whether that's better, although I generally think it is.

      --
      The only thing that stops a bad guy with a compiler is a good guy with a compiler.
      • (Score: 0) by Anonymous Coward on Thursday July 18 2019, @05:59AM

        by Anonymous Coward on Thursday July 18 2019, @05:59AM (#868393)

        I usually use the nested function method. It works fine if the outer loop isn't time sensitive or the language and compiler have decent inline function support, but even then if the innermost loop needs access to the outermost loop's then other methods need to be used.

    • (Score: 2) by fyngyrz on Wednesday July 17 2019, @07:33PM (4 children)

      by fyngyrz (6567) on Wednesday July 17 2019, @07:33PM (#868175) Journal

      I habitually use nested ifs with else clauses that handle most error cases, at least outside of Python. In Python, pretty happy with try, actually. I could learn to use it more effectively... more named exceptions, etc.

      In c and c++ though, I often use the if (thingIsGood) {dostuff} else {shitmyself} form of triage. Lends itself to all kinds of things very nicely, and I can write the cleanup and error stuff almost automatically as I brace it out. Some folks don't like a lot of block nesting, but I'm okay with it.


      if ((ptr1 = some_alloc(whatever)) != NULL)
      {
          if (ptr2 = some_alloc(whatever)) != NULL)
          {
              do_stuff_with_ptrs(ptr1,ptr2);
              some_free(ptr2);
          }
          else
          {
              bitch_and_whine_about_ptr2_and_no_stuff_done_etc();
          }
          some_free(ptr1);
      }
      else
      {
          bitch_and_whine_about_ptr1_and_no_stuff_done_etc();
      }

      --
      Surely not everybody was kung fu fighting?

      • (Score: 0) by Anonymous Coward on Wednesday July 17 2019, @10:26PM (2 children)

        by Anonymous Coward on Wednesday July 17 2019, @10:26PM (#868248)

        There is an obvious problem with that style of error handling: the assertion and the diagnostic message are not in the same place, so suffer from reader locality. Worse, the order of tests and diagnostics are reversed in these nested situations.

        This is much better for readability (pseudo-c):

        attempt
        {
              assert((ptr1 = some_alloc(whatever)) != NULL);
              assert((ptr2 = some_alloc(whatever)) != NULL);
              do_stuff_with_ptrs(ptr1,ptr2);
              some_free(ptr2);
              some_free(ptr1);
        }
        handle_assert(ptr1)
        {
              bitch_and_whine_about_ptr1_and_no_stuff_done_etc();
        }
        handle_assert(ptr2)
        {
              bitch_and_whine_about_ptr2_and_no_stuff_done_etc();
        }

        • (Score: 2) by The Mighty Buzzard on Wednesday July 17 2019, @10:42PM

          by The Mighty Buzzard (18) Subscriber Badge <themightybuzzard@proton.me> on Wednesday July 17 2019, @10:42PM (#868262) Homepage Journal

          That's only a problem if it's not what you deal with every day.

          --
          My rights don't end where your fear begins.
        • (Score: 2) by fyngyrz on Thursday July 18 2019, @11:09AM

          by fyngyrz (6567) on Thursday July 18 2019, @11:09AM (#868440) Journal

          the assertion and the diagnostic message are not in the same place

          They are when they are written, though, because they're the first things to be assembled. request, test, cleanup, report. Once that's done, then you fill the code block.

          Using this successfully is no more than a matter of carefully sequenced code building. Once that's ingrained, it's perfectly reliable and suffers from nothing at all.

          the order of tests and diagnostics are reversed in these nested situations.

          No, they aren't. Test occurs at request time; diagnostic follows immediately if it is called for, otherwise isn't executed. It's not true in a visual read-the-code sense, either. I think you may have misread what I wrote there.

          Also, sigh, missed (at least) a paren in there... I need a pseudo code compiler. :)

          --
          Forget world peace. Visualize using your damned turn signal.

      • (Score: 3, Insightful) by The Mighty Buzzard on Wednesday July 17 2019, @10:46PM

        by The Mighty Buzzard (18) Subscriber Badge <themightybuzzard@proton.me> on Wednesday July 17 2019, @10:46PM (#868264) Homepage Journal

        Therein lies the main reason it doesn't belong in Go. Unless you especially want Go to wind up like Perl where there are multiple commonly used ways of doing anything you can do with a language.

        --
        My rights don't end where your fear begins.
  • (Score: 0) by Anonymous Coward on Wednesday July 17 2019, @07:20PM

    by Anonymous Coward on Wednesday July 17 2019, @07:20PM (#868168)

    Does go have goto?

  • (Score: 2) by inertnet on Wednesday July 17 2019, @08:46PM (7 children)

    by inertnet (4071) on Wednesday July 17 2019, @08:46PM (#868207) Journal

    From the docs [golang.org]:

    OuterLoop:
        for i = 0; i < n; i++ {
            for j = 0; j < m; j++ {
                switch a[i][j] {
                case nil:
                    state = Error
                    break OuterLoop
                case item:
                    state = Found
                    break OuterLoop
                }
            }
        }

    • (Score: 0) by Anonymous Coward on Wednesday July 17 2019, @08:53PM (5 children)

      by Anonymous Coward on Wednesday July 17 2019, @08:53PM (#868213)

      Oh, cool.

      That seems perfectly adequate for eliminating the nest of if's without out adding a try to the language.

      So, given that why would one ask for try?

      • (Score: 2) by Immerman on Thursday July 18 2019, @01:45AM (4 children)

        by Immerman (3985) on Thursday July 18 2019, @01:45AM (#868316)

        From one of the proposals, not sure if this specific one as I followed a few links:

        We propose a new built-in function called try, designed specifically to eliminate the boilerplate if statements typically associated with error handling in Go[...]
        For instance, code such as

        f, err := os.Open(filename)
        if err != nil {
                return …, err // zero values for other results, if any
        }

        can be simplified to

        f := try(os.Open(filename))

        • (Score: 1) by khallow on Thursday July 18 2019, @12:13PM (3 children)

          by khallow (3766) Subscriber Badge on Thursday July 18 2019, @12:13PM (#868464) Journal
          That seems like something that you could put in a library without having to change the code even a little bit. If you have boilerplate, put it in something and do it once.
          • (Score: 2) by Immerman on Thursday July 18 2019, @01:36PM (2 children)

            by Immerman (3985) on Thursday July 18 2019, @01:36PM (#868494)

            Except you can't. You can only return from the current function from within the current function. Moreover "boilerplate code" is rarely identical, which is what you need to stick it in a library. The general pattern of

            if step 1 caused an error
                  Abort
            if step 2 caused an error
                  Abort
            //...
            if step N caused an error
                  Abort

            Is very common in a whole lot of different situations, where steps 1 through N are completely different

            And some sort of language constructs that says
            try to do these things
                    Step 1
                    Step 2
                    //...
                    Step N
            and if there's a problem
                    Abort

            saves a whole lot of redundant code that otherwise that both wastes programmer time to type, and decreases clarity when reading

            In C you could do something like
            if(Step1 == error
            || Step 2 == error
            || ...
            || Step N == error)
                    Abort
            and rely ion the short-circuiting behavior to jump to Abort on the first error. You'll lose all information about what error occurred, but that often doesn't matter. But thanks to Go's multi-return error model I don't think there's a clean way to do that

            • (Score: 1) by khallow on Sunday July 21 2019, @03:41AM (1 child)

              by khallow (3766) Subscriber Badge on Sunday July 21 2019, @03:41AM (#869518) Journal
              So how do they plan to do that with the "try" statement? Something like?

              f := try {
                  Step 1;
                  Step 2;
                  Step 3;
                   ...
              }
              • (Score: 2) by Immerman on Sunday July 21 2019, @07:15PM

                by Immerman (3985) on Sunday July 21 2019, @07:15PM (#869703)

                No, my impression (assuming I didn't end up following a link to some other proposal) was that the specific proposal was for something far less powerful or effective:
                try(step1)
                try(step2)
                etc.

                Where any failure would immediately exit the calling function with the same error. Honestly, I can't think why anyone thought that was a good idea.

                Yours seems like a much better strategy to provide most of the benefit without significantly changing flow control, or being easily confused with a more typical exception-based try statement.

                Of course it would typically need to be followed by an
                if(f!= null){
                //do error handling;
                }
                block, unless you also supported a catch block to replace the redundant test (since a conditional jump must have just occurred to exit the try). A catch with no "parameters" though would also be different enough to not be easily confused with another language.

                And presumably, if you didn't actually care about what error is returned, you could simplify it a bit further by leaving out the f:= part. e.g.
                try{
                step1
                step2
                }
                catch{
                return ... , myError
                }

    • (Score: 0) by Anonymous Coward on Wednesday July 17 2019, @11:44PM

      by Anonymous Coward on Wednesday July 17 2019, @11:44PM (#868285)

      So, Break InnerLoop would also work?
      Cool

  • (Score: 2) by krishnoid on Wednesday July 17 2019, @08:49PM

    by krishnoid (1156) on Wednesday July 17 2019, @08:49PM (#868209)

    Perl gives you the ability to jump to specific parts in a block [perl.org], with an optional label to jump further out syntactically. Breaking out of stack frames, maybe not so much.

  • (Score: 2) by YeaWhatevs on Wednesday July 17 2019, @09:46PM (2 children)

    by YeaWhatevs (5623) on Wednesday July 17 2019, @09:46PM (#868228)

    It's called goto ;)
    I can hear the groaning already, but that would also fix go's error handling.

    • (Score: 2) by darkfeline on Thursday July 18 2019, @02:19AM (1 child)

      by darkfeline (1030) on Thursday July 18 2019, @02:19AM (#868324) Homepage

      Go has goto. For fuck's sake, it wouldn't hurt to do a basic amount of research would it?

      --
      Join the SDF Public Access UNIX System today!