-1

Defering execution of code is commonly used in Go to clean up resources. It's not so often seen but happens that defer is used to execute regular business logic, too. Just as a last step of execution, no matter at which point function hits return keyword.

On Go Blog page, we can find that "defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions."

They do mention about cleaning up but nothing about regular code execution. Obviously, it may execute an arbitrary code, doesn't have to be cleaning up. Is this the best practice, though? Has community any agreement on convention or best practice in this regard?

wst
  • 4,040
  • 4
  • 41
  • 59
  • 4
    The simple rule is: write understandable code. Putting most of the code into cleverly nested defers is not understandable. – Volker Oct 02 '19 at 11:06
  • This is my thought exactly. Instead of putting logic in function in defer, I'd rather put defer logic into other function and then call both, one after another. Much more easy to read the code. It's just my opinion, tho, and I've been curious is there any practice in place. – wst Oct 02 '19 at 16:33

2 Answers2

7

The Go compiler doesn't know what code is clean-up code. So if it works to defer clean-up code, it will obviously work to defer any non-clean-up code too.

There is some overhead for deferred functions, obviously the call stack has to be managed, but if it makes your code safer and / or easier to read, go for it. It's perfectly fine to use it to do any action before a return, even to modify the values being returned, and even in case of panicing. See How to return a value in a Go function that panics?

One thing you should keep in mind: deferred functions are run even if the code panics (which is desirable for clean-up code), which otherwise would not be a normal flow of execution. So this will be a difference when using defer compared to not using it. See related: `defer` in the loop - what will be better?

icza
  • 389,944
  • 63
  • 907
  • 827
  • I’d strongly emphasize “if it makes your code safer or easier to read”. Especially easier to read. If something is hard to read it fails to be safe anyway. – wst Oct 03 '19 at 12:31
3

Let's be very specific about the overhead that Go defer operations currently (pre Go 1.14) add.

As of Go 1.13, most defer operations take about 35ns (reduced from about 50ns in Go 1.12). In contrast, a direct call takes about 6ns. This gap incentivizes engineers to eliminate defer operations from hot code paths, which takes away time from more productive tasks, leads to less maintainable code (e.g., if a panic is later introduced, the "optimization" is no longer correct), and discourages people from using a language feature when it would otherwise be an appropriate solution to a problem.

Proposal: Low-cost defers through inline code, and extra funcdata to manage the panic case

peterSO
  • 158,998
  • 31
  • 281
  • 276