Your 4 misunderstandings about go error handling!

Time:2021-10-24

Your 4 misunderstandings about go error handling!

Hello, I’m fried fish.

GoIn languageerror handlingThe mechanism of has always been a hot issue among gophers. It has even been hoped that go supports throw and catch keywords to achieve features similar to other languages. Discussions in the community never stopped.

Today, fried fish takes you to know some problems that you are most concerned about and most likely to be misunderstood and despised in the error handling of go language:

  • Why not support try catch?
  • Why not support the mechanism of global capture?
  • Why design error handling like this?
  • What will be the future error handling mechanism?

Lonely try catch

In go1, we know that it is almost impossible to support. So I had the idea of GO2. Why can’t go support try catch combination boxing?

The concept of GO2 was publicized last year, so in 2020, a small partner took the opportunity to put forward a proposal similar to proposal: go 2: use keywords throw, catch, and guard to handle errors [1], which is supported by other languages. What happened to go language?

The following is a demonstration from the proposal, go1 error handling:

  1. type data struct {} 
  2.  
  3. func (d data) bar() (string, error) { 
  4.     return “”, errors.New(“err”) 
  5.  
  6. func foo() (data, error) { 
  7.     return data{}, errors.New(“err”) 
  8.  
  9. func do () (string, error) { 
  10.     d, err := foo() 
  11.     if err != nil { 
  12.         return “”, err 
  13.     } 
  14.  
  15.     s, err := d.bar() 
  16.     if err != nil { 
  17.         return “”, err 
  18.     } 
  19.  
  20.     return s, nil 

The way the new proposal changes:

  1. type data struct {} 
  2.  
  3. func (d data) bar() string { 
  4.     throw “”, errors.New(“err”) 
  5.  
  6. func foo() (d data) { 
  7.     throw errors.New(“err”) 
  8.     return 
  9.  
  10. func do () (string, error) { 
  11.     catch err { 
  12.         return “”, err  
  13.     } 
  14.  
  15.     s := foo().bar() 
  16.     return s, nil 

However, the reply was very clear, @ davecheney replied “in the strongest possible terms, no” at the bottom. This is confusing. Why is it so hard?

In fact, the go official has clearly mentioned in the proposal of error handling – problem overview [2], and the go official will consciously choose to use explicit error results and explicit error checking in design.

According to language: go 2: error handling meta issue [3], the main reasons for rejecting the try catch keyword are:

  • Additional process control will be involved, because using the complex expression of try will cause the function to return unexpectedly.
  • At the expression level, there is no process control structure, only the panic keyword, which is not just returned from a function.

To put it bluntly, the design concept is inconsistent, and the implementation is not reasonable. In previous rounds of discussions, it has long been rejected by the go team.

On the contrary, the go team answered this question over and over again. It was impatient and directly sorted out the FAQs in the issues version.

Want to capture all panic

In go language, there is a point that many new students will encounter differently. That is, in goroutine, if the panic is not added and the recover keyword is not added (sometimes forgotten), the program will crash.

Or think that adding recover can protect the panic generated by a goroutine derived from a goroutine once and for all.

But the reality is always confusing. I often see students raise similar doubts:

Your 4 misunderstandings about go error handling!

From go reader exchange group

At this time, some students with other language experience thought of a sharp weapon. Can you set a global error handler.

For example, PHP language can also have similar methods:

  1. set_error_handler(); 
  2. set_exception_handler(); 
  3. register_shutdown_function(); 

Obviously, there is nothing similar in go language. To categorize, we focus on the following two issues:

  • Why can’t recover capture higher-level panic?
  • Why doesn’t go have a global error handling method?

Source level

If you are talking about design, you can know it only through the GMP model of go and the source code analysis of defer + panic + recver.

Your 4 misunderstandings about go error handling!

In essence, defer + panic are all mounted on G. you can have more in-depth understanding by looking at the in-depth understanding of go panic and recover [4] I wrote before.

design idea

In this article, we can’t be limited to the source code. We need to dig deeper. What is the idea of the go designer and why it doesn’t support it?

In go issues, proposal: spec: allow fatal panic handler [5] and no way to catch errors from goroutines automatically [6] have discussed the above problems respectively.

The head of the Go Team @ Russ Cox gave a clear answer: the design position of the go language is that error recovery should be completed locally or completely in a separate process.

Your 4 misunderstandings about go error handling!

This is the fundamental reason why go language cannot recover from panic or throw across goroutines, which is determined by the idea of language design.

When analyzing the source code, the whole set of GMP + defer + panic + recover mechanism you see is written and developed with this design idea.

The design idea determines the source code implementation.

Suggested way

At present, the possibility of shaking this design idea from the go language level is very low. At least 2021 has not seen a change now.

On the whole, it is suggested to provide a public go method to avoid this situation. Examples provided by reference issues are as follows:

  1. recovery.SafeGo(logger, func() { 
  2.     method(all parameters) 
  3. }) 
  4.  
  5. func SafeGo(logger logging.ILogger, f func()) { 
  6.  go func() { 
  7.   defer func() { 
  8.    if panicMessage := recover(); panicMessage != nil { 
  9.     … 
  10.    } 
  11.   }() 
  12.  
  13.   f() 
  14.  }() 

Does it feel like deja vu?

Every company’s internal library should have such a tool and method to avoid the strange problems caused by the occasionally forgotten goroutine recover.

You can also refer to the suggestion to use a separate process (goroutine in go language) to handle these panics uniformly, but this is troublesome and rare.

What will happen in the future

The go community is very concerned about the future error handling mechanism of the go language, because go1 has already made a meal, and hopes to solve the problem of error handling mechanism on GO2.

The GO2 core is expected to handle the following points (#40432):

For GO2, we want to make error checking easier and reduce the number of Go program code dedicated to error checking. We also want to make writing error handling more convenient and reduce the possibility that programmers spend time writing error handling.

Both error checking and error handling must be clear, that is, visible in the program text. We don’t want to repeat the trap of exception handling.

The existing code must continue to work and remain as valid as it is now. Any changes must be coordinated with the existing code.

To this end, many people have put forward many new proposals… Unfortunately, by the end of August 2021, many people have tried to change the language level to achieve these goals, but no new proposal has been accepted.

There are also many changes incorporated into the GO2 proposal, mainly the optimization of error handling.

If you are interested, you can take a look at my previous book, “preview, GO2 error’s struggle”, which I believe can bring you a lot of new knowledge.

summary

Seeing here, we can’t help thinking. Why, why, in the 21st century, the former has so many excellent languages, and the error handling mechanism of go language is still so difficult to choose?

Obviously, the development team of go language has its own design philosophy and thought, otherwise “less is more” will not be so widely spread. It will be better for our future programming to understand the official idea of go instead of one-way understanding.

Of course, there are a series of problems that are both necessary and difficult to deal with. You are welcome to pay attention to the fried fish. We can also continue to pay attention to and discuss the follow-up error handling of go!

reference material

[1]proposal: Go 2: use keywords throw, catch, and guard to handle errors: https://github.com/golang/go/issues/40583

[2]Error Handling — Problem Overview: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md

[3]language: Go 2: error handling meta issue: https://github.com/golang/go/issues/40432

[4] Go panic and recover: https://eddycjy.com/posts/go/panic/2019-05-21-panic-and-recover/

[5]proposal: spec: allow fatal panic handler: https://github.com/golang/go/issues/32333

[6]No way to catch errors from goroutines automatically: https://github.com/golang/go/issues/20161